FILE
c3-isp-resizer.c
File preview with syntax highlighting.
linux-6.19.14/drivers/media/platform/amlogic/c3/isp/c3-isp-resizer.c
1// SPDX-License-Identifier: (GPL-2.0-only OR MIT) 2/* 3 * Copyright (C) 2024 Amlogic, Inc. All rights reserved 4 */ 5 6#include <linux/pm_runtime.h> 7 8#include "c3-isp-common.h" 9#include "c3-isp-regs.h" 10 11#define C3_ISP_RSZ_DEF_PAD_FMT MEDIA_BUS_FMT_YUV10_1X30 12#define C3_ISP_DISP_REG(base, id) ((base) + (id) * 0x400) 13#define C3_ISP_PPS_LUT_H_NUM 33 14#define C3_ISP_PPS_LUT_CTYPE_0 0 15#define C3_ISP_PPS_LUT_CTYPE_2 2 16#define C3_ISP_SCL_EN 1 17#define C3_ISP_SCL_DIS 0 18 19/* 20 * struct c3_isp_rsz_format_info - ISP resizer format information 21 * 22 * @mbus_code: the mbus code 23 * @pads: bitmask detailing valid pads for this mbus_code 24 * @is_raw: the raw format flag of mbus code 25 */ 26struct c3_isp_rsz_format_info { 27 u32 mbus_code; 28 u32 pads; 29 bool is_raw; 30}; 31 32static const struct c3_isp_rsz_format_info c3_isp_rsz_fmts[] = { 33 /* RAW formats */ 34 { 35 .mbus_code = MEDIA_BUS_FMT_SBGGR16_1X16, 36 .pads = BIT(C3_ISP_RSZ_PAD_SINK) 37 | BIT(C3_ISP_RSZ_PAD_SOURCE), 38 .is_raw = true, 39 }, { 40 .mbus_code = MEDIA_BUS_FMT_SGBRG16_1X16, 41 .pads = BIT(C3_ISP_RSZ_PAD_SINK) 42 | BIT(C3_ISP_RSZ_PAD_SOURCE), 43 .is_raw = true, 44 }, { 45 .mbus_code = MEDIA_BUS_FMT_SGRBG16_1X16, 46 .pads = BIT(C3_ISP_RSZ_PAD_SINK) 47 | BIT(C3_ISP_RSZ_PAD_SOURCE), 48 .is_raw = true, 49 }, { 50 .mbus_code = MEDIA_BUS_FMT_SRGGB16_1X16, 51 .pads = BIT(C3_ISP_RSZ_PAD_SINK) 52 | BIT(C3_ISP_RSZ_PAD_SOURCE), 53 .is_raw = true, 54 }, 55 /* YUV formats */ 56 { 57 .mbus_code = MEDIA_BUS_FMT_YUV10_1X30, 58 .pads = BIT(C3_ISP_RSZ_PAD_SINK) 59 | BIT(C3_ISP_RSZ_PAD_SOURCE), 60 .is_raw = false, 61 }, 62}; 63 64/* 65 * struct c3_isp_pps_io_size - ISP scaler input and output size 66 * 67 * @thsize: input horizontal size of after preprocessing 68 * @tvsize: input vertical size of after preprocessing 69 * @ohsize: output horizontal size 70 * @ovsize: output vertical size 71 * @ihsize: input horizontal size 72 * @max_hsize: maximum horizontal size 73 */ 74struct c3_isp_pps_io_size { 75 u32 thsize; 76 u32 tvsize; 77 u32 ohsize; 78 u32 ovsize; 79 u32 ihsize; 80 u32 max_hsize; 81}; 82 83/* The normal parameters of pps module */ 84static const int c3_isp_pps_lut[C3_ISP_PPS_LUT_H_NUM][4] = { 85 { 0, 511, 0, 0}, { -5, 511, 5, 0}, {-10, 511, 11, 0}, 86 {-14, 510, 17, -1}, {-18, 508, 23, -1}, {-22, 506, 29, -1}, 87 {-25, 503, 36, -2}, {-28, 500, 43, -3}, {-32, 496, 51, -3}, 88 {-34, 491, 59, -4}, {-37, 487, 67, -5}, {-39, 482, 75, -6}, 89 {-41, 476, 84, -7}, {-42, 470, 92, -8}, {-44, 463, 102, -9}, 90 {-45, 456, 111, -10}, {-45, 449, 120, -12}, {-47, 442, 130, -13}, 91 {-47, 434, 140, -15}, {-47, 425, 151, -17}, {-47, 416, 161, -18}, 92 {-47, 407, 172, -20}, {-47, 398, 182, -21}, {-47, 389, 193, -23}, 93 {-46, 379, 204, -25}, {-45, 369, 215, -27}, {-44, 358, 226, -28}, 94 {-43, 348, 237, -30}, {-43, 337, 249, -31}, {-41, 326, 260, -33}, 95 {-40, 316, 271, -35}, {-39, 305, 282, -36}, {-37, 293, 293, -37} 96}; 97 98static const struct c3_isp_rsz_format_info 99*rsz_find_format_by_code(u32 code, u32 pad) 100{ 101 for (unsigned int i = 0; i < ARRAY_SIZE(c3_isp_rsz_fmts); i++) { 102 const struct c3_isp_rsz_format_info *info = &c3_isp_rsz_fmts[i]; 103 104 if (info->mbus_code == code && info->pads & BIT(pad)) 105 return info; 106 } 107 108 return NULL; 109} 110 111static const struct c3_isp_rsz_format_info 112*rsz_find_format_by_index(u32 index, u32 pad) 113{ 114 for (unsigned int i = 0; i < ARRAY_SIZE(c3_isp_rsz_fmts); i++) { 115 const struct c3_isp_rsz_format_info *info = &c3_isp_rsz_fmts[i]; 116 117 if (!(info->pads & BIT(pad))) 118 continue; 119 120 if (!index) 121 return info; 122 123 index--; 124 } 125 126 return NULL; 127} 128 129static void c3_isp_rsz_pps_size(struct c3_isp_resizer *rsz, 130 struct c3_isp_pps_io_size *io_size) 131{ 132 int thsize = io_size->thsize; 133 int tvsize = io_size->tvsize; 134 u32 ohsize = io_size->ohsize; 135 u32 ovsize = io_size->ovsize; 136 u32 ihsize = io_size->ihsize; 137 u32 max_hsize = io_size->max_hsize; 138 int h_int; 139 int v_int; 140 int h_fract; 141 int v_fract; 142 int yuv444to422_en; 143 144 /* Calculate the integer part of horizonal scaler step */ 145 h_int = thsize / ohsize; 146 147 /* Calculate the vertical part of horizonal scaler step */ 148 v_int = tvsize / ovsize; 149 150 /* 151 * Calculate the fraction part of horizonal scaler step. 152 * step_h_fraction = (source / dest) * 2^24, 153 * so step_h_fraction = ((source << 12) / dest) << 12. 154 */ 155 h_fract = ((thsize << 12) / ohsize) << 12; 156 157 /* 158 * Calculate the fraction part of vertical scaler step 159 * step_v_fraction = (source / dest) * 2^24, 160 * so step_v_fraction = ((source << 12) / dest) << 12. 161 */ 162 v_fract = ((tvsize << 12) / ovsize) << 12; 163 164 yuv444to422_en = ihsize > (max_hsize / 2) ? 1 : 0; 165 166 c3_isp_update_bits(rsz->isp, 167 C3_ISP_DISP_REG(DISP0_PPS_444TO422, rsz->id), 168 DISP0_PPS_444TO422_EN_MASK, 169 DISP0_PPS_444TO422_EN(yuv444to422_en)); 170 171 c3_isp_write(rsz->isp, 172 C3_ISP_DISP_REG(DISP0_PPS_VSC_START_PHASE_STEP, rsz->id), 173 DISP0_PPS_VSC_START_PHASE_STEP_VERT_FRAC(v_fract) | 174 DISP0_PPS_VSC_START_PHASE_STEP_VERT_INTE(v_int)); 175 176 c3_isp_write(rsz->isp, 177 C3_ISP_DISP_REG(DISP0_PPS_HSC_START_PHASE_STEP, rsz->id), 178 DISP0_PPS_HSC_START_PHASE_STEP_HORIZ_FRAC(h_fract) | 179 DISP0_PPS_HSC_START_PHASE_STEP_HORIZ_INTE(h_int)); 180} 181 182static void c3_isp_rsz_pps_lut(struct c3_isp_resizer *rsz, u32 ctype) 183{ 184 unsigned int i; 185 186 /* 187 * Default value of this register is 0, so only need to set 188 * SCALE_LUMA_COEF_S11_MODE and SCALE_LUMA_CTYPE. This register needs 189 * to be written in one time. 190 */ 191 c3_isp_write(rsz->isp, 192 C3_ISP_DISP_REG(ISP_SCALE0_COEF_IDX_LUMA, rsz->id), 193 ISP_SCALE0_COEF_IDX_LUMA_COEF_S11_MODE_EN | 194 ISP_SCALE0_COEF_IDX_LUMA_CTYPE(ctype)); 195 196 for (i = 0; i < C3_ISP_PPS_LUT_H_NUM; i++) { 197 c3_isp_write(rsz->isp, 198 C3_ISP_DISP_REG(ISP_SCALE0_COEF_LUMA, rsz->id), 199 ISP_SCALE0_COEF_LUMA_DATA0(c3_isp_pps_lut[i][0]) | 200 ISP_SCALE0_COEF_LUMA_DATA1(c3_isp_pps_lut[i][1])); 201 c3_isp_write(rsz->isp, 202 C3_ISP_DISP_REG(ISP_SCALE0_COEF_LUMA, rsz->id), 203 ISP_SCALE0_COEF_LUMA_DATA0(c3_isp_pps_lut[i][2]) | 204 ISP_SCALE0_COEF_LUMA_DATA1(c3_isp_pps_lut[i][3])); 205 } 206 207 /* 208 * Default value of this register is 0, so only need to set 209 * SCALE_CHRO_COEF_S11_MODE and SCALE_CHRO_CTYPE. This register needs 210 * to be written in one time. 211 */ 212 c3_isp_write(rsz->isp, 213 C3_ISP_DISP_REG(ISP_SCALE0_COEF_IDX_CHRO, rsz->id), 214 ISP_SCALE0_COEF_IDX_CHRO_COEF_S11_MODE_EN | 215 ISP_SCALE0_COEF_IDX_CHRO_CTYPE(ctype)); 216 217 for (i = 0; i < C3_ISP_PPS_LUT_H_NUM; i++) { 218 c3_isp_write(rsz->isp, 219 C3_ISP_DISP_REG(ISP_SCALE0_COEF_CHRO, rsz->id), 220 ISP_SCALE0_COEF_CHRO_DATA0(c3_isp_pps_lut[i][0]) | 221 ISP_SCALE0_COEF_CHRO_DATA1(c3_isp_pps_lut[i][1])); 222 c3_isp_write(rsz->isp, 223 C3_ISP_DISP_REG(ISP_SCALE0_COEF_CHRO, rsz->id), 224 ISP_SCALE0_COEF_CHRO_DATA0(c3_isp_pps_lut[i][2]) | 225 ISP_SCALE0_COEF_CHRO_DATA1(c3_isp_pps_lut[i][3])); 226 } 227} 228 229static void c3_isp_rsz_pps_disable(struct c3_isp_resizer *rsz) 230{ 231 c3_isp_update_bits(rsz->isp, 232 C3_ISP_DISP_REG(DISP0_PPS_SCALE_EN, rsz->id), 233 DISP0_PPS_SCALE_EN_HSC_EN_MASK, 234 DISP0_PPS_SCALE_EN_HSC_DIS); 235 c3_isp_update_bits(rsz->isp, 236 C3_ISP_DISP_REG(DISP0_PPS_SCALE_EN, rsz->id), 237 DISP0_PPS_SCALE_EN_VSC_EN_MASK, 238 DISP0_PPS_SCALE_EN_VSC_DIS); 239 c3_isp_update_bits(rsz->isp, 240 C3_ISP_DISP_REG(DISP0_PPS_SCALE_EN, rsz->id), 241 DISP0_PPS_SCALE_EN_PREVSC_EN_MASK, 242 DISP0_PPS_SCALE_EN_PREVSC_DIS); 243 c3_isp_update_bits(rsz->isp, 244 C3_ISP_DISP_REG(DISP0_PPS_SCALE_EN, rsz->id), 245 DISP0_PPS_SCALE_EN_PREHSC_EN_MASK, 246 DISP0_PPS_SCALE_EN_PREHSC_DIS); 247} 248 249static int c3_isp_rsz_pps_enable(struct c3_isp_resizer *rsz, 250 struct v4l2_subdev_state *state) 251{ 252 struct v4l2_rect *crop; 253 struct v4l2_rect *cmps; 254 int max_hsize; 255 int hsc_en, vsc_en; 256 int preh_en, prev_en; 257 u32 prehsc_rate; 258 u32 prevsc_flt_num; 259 int pre_vscale_max_hsize; 260 u32 ihsize_after_pre_hsc; 261 u32 ihsize_after_pre_hsc_alt; 262 u32 vsc_tap_num_alt; 263 u32 ihsize; 264 u32 ivsize; 265 struct c3_isp_pps_io_size io_size; 266 267 crop = v4l2_subdev_state_get_crop(state, C3_ISP_RSZ_PAD_SINK); 268 cmps = v4l2_subdev_state_get_compose(state, C3_ISP_RSZ_PAD_SINK); 269 270 ihsize = crop->width; 271 ivsize = crop->height; 272 273 hsc_en = (ihsize == cmps->width) ? C3_ISP_SCL_DIS : C3_ISP_SCL_EN; 274 vsc_en = (ivsize == cmps->height) ? C3_ISP_SCL_DIS : C3_ISP_SCL_EN; 275 276 /* Disable pps when there no need to use pps */ 277 if (!hsc_en && !vsc_en) { 278 c3_isp_rsz_pps_disable(rsz); 279 return 0; 280 } 281 282 /* Pre-scale needs to be enable if the down scaling factor exceeds 4 */ 283 preh_en = (ihsize > cmps->width * 4) ? C3_ISP_SCL_EN : C3_ISP_SCL_DIS; 284 prev_en = (ivsize > cmps->height * 4) ? C3_ISP_SCL_EN : C3_ISP_SCL_DIS; 285 286 if (rsz->id == C3_ISP_RSZ_2) { 287 max_hsize = C3_ISP_MAX_WIDTH; 288 289 /* Set vertical tap number */ 290 prevsc_flt_num = 4; 291 292 /* Set the max hsize of pre-vertical scale */ 293 pre_vscale_max_hsize = max_hsize / 2; 294 } else { 295 max_hsize = C3_ISP_DEFAULT_WIDTH; 296 297 /* Set vertical tap number and the max hsize of pre-vertical */ 298 if (ihsize > (max_hsize / 2) && 299 ihsize <= max_hsize && prev_en) { 300 prevsc_flt_num = 2; 301 pre_vscale_max_hsize = max_hsize; 302 } else { 303 prevsc_flt_num = 4; 304 pre_vscale_max_hsize = max_hsize / 2; 305 } 306 } 307 308 /* 309 * Set pre-horizonal scale rate and the hsize of after 310 * pre-horizonal scale. 311 */ 312 if (preh_en) { 313 prehsc_rate = 1; 314 ihsize_after_pre_hsc = DIV_ROUND_UP(ihsize, 2); 315 } else { 316 prehsc_rate = 0; 317 ihsize_after_pre_hsc = ihsize; 318 } 319 320 /* Change pre-horizonal scale rate */ 321 if (prev_en && ihsize_after_pre_hsc >= pre_vscale_max_hsize) 322 prehsc_rate += 1; 323 324 /* Set the actual hsize of after pre-horizonal scale */ 325 if (preh_en) 326 ihsize_after_pre_hsc_alt = 327 DIV_ROUND_UP(ihsize, 1 << prehsc_rate); 328 else 329 ihsize_after_pre_hsc_alt = ihsize; 330 331 /* Set vertical scaler bank length */ 332 if (ihsize_after_pre_hsc_alt <= (max_hsize / 2)) 333 vsc_tap_num_alt = 4; 334 else if (ihsize_after_pre_hsc_alt <= max_hsize) 335 vsc_tap_num_alt = prev_en ? 2 : 4; 336 else 337 vsc_tap_num_alt = prev_en ? 4 : 2; 338 339 io_size.thsize = ihsize_after_pre_hsc_alt; 340 io_size.tvsize = prev_en ? DIV_ROUND_UP(ivsize, 2) : ivsize; 341 io_size.ohsize = cmps->width; 342 io_size.ovsize = cmps->height; 343 io_size.ihsize = ihsize; 344 io_size.max_hsize = max_hsize; 345 346 c3_isp_rsz_pps_size(rsz, &io_size); 347 c3_isp_rsz_pps_lut(rsz, C3_ISP_PPS_LUT_CTYPE_0); 348 c3_isp_rsz_pps_lut(rsz, C3_ISP_PPS_LUT_CTYPE_2); 349 350 c3_isp_update_bits(rsz->isp, 351 C3_ISP_DISP_REG(DISP0_PPS_SCALE_EN, rsz->id), 352 DISP0_PPS_SCALE_EN_VSC_TAP_NUM_MASK, 353 DISP0_PPS_SCALE_EN_VSC_TAP_NUM(vsc_tap_num_alt)); 354 c3_isp_update_bits(rsz->isp, 355 C3_ISP_DISP_REG(DISP0_PPS_SCALE_EN, rsz->id), 356 DISP0_PPS_SCALE_EN_PREVSC_FLT_NUM_MASK, 357 DISP0_PPS_SCALE_EN_PREVSC_FLT_NUM(prevsc_flt_num)); 358 359 c3_isp_update_bits(rsz->isp, 360 C3_ISP_DISP_REG(DISP0_PPS_SCALE_EN, rsz->id), 361 DISP0_PPS_SCALE_EN_PREVSC_RATE_MASK, 362 DISP0_PPS_SCALE_EN_PREVSC_RATE(prev_en)); 363 c3_isp_update_bits(rsz->isp, 364 C3_ISP_DISP_REG(DISP0_PPS_SCALE_EN, rsz->id), 365 DISP0_PPS_SCALE_EN_PREHSC_RATE_MASK, 366 DISP0_PPS_SCALE_EN_PREHSC_RATE(prehsc_rate)); 367 368 c3_isp_update_bits(rsz->isp, 369 C3_ISP_DISP_REG(DISP0_PPS_SCALE_EN, rsz->id), 370 DISP0_PPS_SCALE_EN_HSC_EN_MASK, 371 DISP0_PPS_SCALE_EN_HSC_EN(hsc_en)); 372 c3_isp_update_bits(rsz->isp, 373 C3_ISP_DISP_REG(DISP0_PPS_SCALE_EN, rsz->id), 374 DISP0_PPS_SCALE_EN_VSC_EN_MASK, 375 DISP0_PPS_SCALE_EN_VSC_EN(vsc_en)); 376 c3_isp_update_bits(rsz->isp, 377 C3_ISP_DISP_REG(DISP0_PPS_SCALE_EN, rsz->id), 378 DISP0_PPS_SCALE_EN_PREVSC_EN_MASK, 379 DISP0_PPS_SCALE_EN_PREVSC_EN(prev_en)); 380 c3_isp_update_bits(rsz->isp, 381 C3_ISP_DISP_REG(DISP0_PPS_SCALE_EN, rsz->id), 382 DISP0_PPS_SCALE_EN_PREHSC_EN_MASK, 383 DISP0_PPS_SCALE_EN_PREHSC_EN(preh_en)); 384 385 c3_isp_update_bits(rsz->isp, 386 C3_ISP_DISP_REG(DISP0_PPS_SCALE_EN, rsz->id), 387 DISP0_PPS_SCALE_EN_HSC_NOR_RS_BITS_MASK, 388 DISP0_PPS_SCALE_EN_HSC_NOR_RS_BITS(9)); 389 c3_isp_update_bits(rsz->isp, 390 C3_ISP_DISP_REG(DISP0_PPS_SCALE_EN, rsz->id), 391 DISP0_PPS_SCALE_EN_VSC_NOR_RS_BITS_MASK, 392 DISP0_PPS_SCALE_EN_VSC_NOR_RS_BITS(9)); 393 394 return 0; 395} 396 397static void c3_isp_rsz_start(struct c3_isp_resizer *rsz, 398 struct v4l2_subdev_state *state) 399{ 400 struct v4l2_mbus_framefmt *sink_fmt; 401 struct v4l2_mbus_framefmt *src_fmt; 402 const struct c3_isp_rsz_format_info *rsz_fmt; 403 struct v4l2_rect *sink_crop; 404 u32 mask; 405 u32 val; 406 407 sink_fmt = v4l2_subdev_state_get_format(state, C3_ISP_RSZ_PAD_SINK); 408 sink_crop = v4l2_subdev_state_get_crop(state, C3_ISP_RSZ_PAD_SINK); 409 src_fmt = v4l2_subdev_state_get_format(state, C3_ISP_RSZ_PAD_SOURCE); 410 rsz_fmt = rsz_find_format_by_code(sink_fmt->code, C3_ISP_RSZ_PAD_SINK); 411 412 if (rsz->id == C3_ISP_RSZ_0) { 413 mask = ISP_TOP_DISPIN_SEL_DISP0_MASK; 414 val = rsz_fmt->is_raw ? ISP_TOP_DISPIN_SEL_DISP0_MIPI_OUT 415 : ISP_TOP_DISPIN_SEL_DISP0_CORE_OUT; 416 } else if (rsz->id == C3_ISP_RSZ_1) { 417 mask = ISP_TOP_DISPIN_SEL_DISP1_MASK; 418 val = rsz_fmt->is_raw ? ISP_TOP_DISPIN_SEL_DISP1_MIPI_OUT 419 : ISP_TOP_DISPIN_SEL_DISP1_CORE_OUT; 420 } else { 421 mask = ISP_TOP_DISPIN_SEL_DISP2_MASK; 422 val = rsz_fmt->is_raw ? ISP_TOP_DISPIN_SEL_DISP2_MIPI_OUT 423 : ISP_TOP_DISPIN_SEL_DISP2_CORE_OUT; 424 } 425 426 c3_isp_update_bits(rsz->isp, ISP_TOP_DISPIN_SEL, mask, val); 427 428 c3_isp_write(rsz->isp, C3_ISP_DISP_REG(ISP_DISP0_TOP_IN_SIZE, rsz->id), 429 ISP_DISP0_TOP_IN_SIZE_HSIZE(sink_fmt->width) | 430 ISP_DISP0_TOP_IN_SIZE_VSIZE(sink_fmt->height)); 431 432 c3_isp_write(rsz->isp, C3_ISP_DISP_REG(DISP0_TOP_CRP2_START, rsz->id), 433 DISP0_TOP_CRP2_START_V_START(sink_crop->top) | 434 DISP0_TOP_CRP2_START_H_START(sink_crop->left)); 435 436 c3_isp_write(rsz->isp, C3_ISP_DISP_REG(DISP0_TOP_CRP2_SIZE, rsz->id), 437 DISP0_TOP_CRP2_SIZE_V_SIZE(sink_crop->height) | 438 DISP0_TOP_CRP2_SIZE_H_SIZE(sink_crop->width)); 439 440 c3_isp_update_bits(rsz->isp, 441 C3_ISP_DISP_REG(DISP0_TOP_TOP_CTRL, rsz->id), 442 DISP0_TOP_TOP_CTRL_CROP2_EN_MASK, 443 DISP0_TOP_TOP_CTRL_CROP2_EN); 444 445 if (!rsz_fmt->is_raw) 446 c3_isp_rsz_pps_enable(rsz, state); 447 448 c3_isp_update_bits(rsz->isp, 449 C3_ISP_DISP_REG(DISP0_TOP_OUT_SIZE, rsz->id), 450 DISP0_TOP_OUT_SIZE_SCL_OUT_HEIGHT_MASK, 451 DISP0_TOP_OUT_SIZE_SCL_OUT_HEIGHT(src_fmt->height)); 452 c3_isp_update_bits(rsz->isp, 453 C3_ISP_DISP_REG(DISP0_TOP_OUT_SIZE, rsz->id), 454 DISP0_TOP_OUT_SIZE_SCL_OUT_WIDTH_MASK, 455 DISP0_TOP_OUT_SIZE_SCL_OUT_WIDTH(src_fmt->width)); 456 457 if (rsz->id == C3_ISP_RSZ_0) { 458 mask = ISP_TOP_PATH_EN_DISP0_EN_MASK; 459 val = ISP_TOP_PATH_EN_DISP0_EN; 460 } else if (rsz->id == C3_ISP_RSZ_1) { 461 mask = ISP_TOP_PATH_EN_DISP1_EN_MASK; 462 val = ISP_TOP_PATH_EN_DISP1_EN; 463 } else { 464 mask = ISP_TOP_PATH_EN_DISP2_EN_MASK; 465 val = ISP_TOP_PATH_EN_DISP2_EN; 466 } 467 468 c3_isp_update_bits(rsz->isp, ISP_TOP_PATH_EN, mask, val); 469} 470 471static void c3_isp_rsz_stop(struct c3_isp_resizer *rsz) 472{ 473 u32 mask; 474 u32 val; 475 476 if (rsz->id == C3_ISP_RSZ_0) { 477 mask = ISP_TOP_PATH_EN_DISP0_EN_MASK; 478 val = ISP_TOP_PATH_EN_DISP0_DIS; 479 } else if (rsz->id == C3_ISP_RSZ_1) { 480 mask = ISP_TOP_PATH_EN_DISP1_EN_MASK; 481 val = ISP_TOP_PATH_EN_DISP1_DIS; 482 } else { 483 mask = ISP_TOP_PATH_EN_DISP2_EN_MASK; 484 val = ISP_TOP_PATH_EN_DISP2_DIS; 485 } 486 487 c3_isp_update_bits(rsz->isp, ISP_TOP_PATH_EN, mask, val); 488 489 c3_isp_update_bits(rsz->isp, 490 C3_ISP_DISP_REG(DISP0_TOP_TOP_CTRL, rsz->id), 491 DISP0_TOP_TOP_CTRL_CROP2_EN_MASK, 492 DISP0_TOP_TOP_CTRL_CROP2_DIS); 493 494 c3_isp_rsz_pps_disable(rsz); 495} 496 497static int c3_isp_rsz_enable_streams(struct v4l2_subdev *sd, 498 struct v4l2_subdev_state *state, 499 u32 pad, u64 streams_mask) 500{ 501 struct c3_isp_resizer *rsz = v4l2_get_subdevdata(sd); 502 503 c3_isp_rsz_start(rsz, state); 504 505 c3_isp_params_pre_cfg(rsz->isp); 506 c3_isp_stats_pre_cfg(rsz->isp); 507 508 return v4l2_subdev_enable_streams(rsz->src_sd, rsz->src_pad, BIT(0)); 509} 510 511static int c3_isp_rsz_disable_streams(struct v4l2_subdev *sd, 512 struct v4l2_subdev_state *state, 513 u32 pad, u64 streams_mask) 514{ 515 struct c3_isp_resizer *rsz = v4l2_get_subdevdata(sd); 516 517 c3_isp_rsz_stop(rsz); 518 519 return v4l2_subdev_disable_streams(rsz->src_sd, rsz->src_pad, BIT(0)); 520} 521 522static int c3_isp_rsz_enum_mbus_code(struct v4l2_subdev *sd, 523 struct v4l2_subdev_state *state, 524 struct v4l2_subdev_mbus_code_enum *code) 525{ 526 const struct c3_isp_rsz_format_info *info; 527 528 info = rsz_find_format_by_index(code->index, code->pad); 529 if (!info) 530 return -EINVAL; 531 532 code->code = info->mbus_code; 533 534 return 0; 535} 536 537static void c3_isp_rsz_set_sink_fmt(struct v4l2_subdev_state *state, 538 struct v4l2_subdev_format *format) 539{ 540 struct v4l2_mbus_framefmt *sink_fmt; 541 struct v4l2_mbus_framefmt *src_fmt; 542 struct v4l2_rect *sink_crop; 543 struct v4l2_rect *sink_cmps; 544 const struct c3_isp_rsz_format_info *rsz_fmt; 545 546 sink_fmt = v4l2_subdev_state_get_format(state, format->pad); 547 sink_crop = v4l2_subdev_state_get_crop(state, format->pad); 548 sink_cmps = v4l2_subdev_state_get_compose(state, format->pad); 549 src_fmt = v4l2_subdev_state_get_format(state, C3_ISP_RSZ_PAD_SOURCE); 550 551 rsz_fmt = rsz_find_format_by_code(format->format.code, format->pad); 552 if (rsz_fmt) 553 sink_fmt->code = format->format.code; 554 else 555 sink_fmt->code = C3_ISP_RSZ_DEF_PAD_FMT; 556 557 sink_fmt->width = clamp_t(u32, format->format.width, 558 C3_ISP_MIN_WIDTH, C3_ISP_MAX_WIDTH); 559 sink_fmt->height = clamp_t(u32, format->format.height, 560 C3_ISP_MIN_HEIGHT, C3_ISP_MAX_HEIGHT); 561 sink_fmt->field = V4L2_FIELD_NONE; 562 sink_fmt->ycbcr_enc = V4L2_YCBCR_ENC_601; 563 564 if (rsz_fmt && rsz_fmt->is_raw) { 565 sink_fmt->colorspace = V4L2_COLORSPACE_RAW; 566 sink_fmt->xfer_func = V4L2_XFER_FUNC_NONE; 567 sink_fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE; 568 } else { 569 sink_fmt->colorspace = V4L2_COLORSPACE_SRGB; 570 sink_fmt->xfer_func = V4L2_XFER_FUNC_SRGB; 571 sink_fmt->quantization = V4L2_QUANTIZATION_LIM_RANGE; 572 } 573 574 sink_crop->width = sink_fmt->width; 575 sink_crop->height = sink_fmt->height; 576 sink_crop->left = 0; 577 sink_crop->top = 0; 578 579 sink_cmps->width = sink_crop->width; 580 sink_cmps->height = sink_crop->height; 581 sink_cmps->left = 0; 582 sink_cmps->top = 0; 583 584 src_fmt->code = sink_fmt->code; 585 src_fmt->width = sink_cmps->width; 586 src_fmt->height = sink_cmps->height; 587 588 format->format = *sink_fmt; 589} 590 591static void c3_isp_rsz_set_source_fmt(struct v4l2_subdev_state *state, 592 struct v4l2_subdev_format *format) 593{ 594 struct v4l2_mbus_framefmt *src_fmt; 595 struct v4l2_mbus_framefmt *sink_fmt; 596 struct v4l2_rect *sink_cmps; 597 const struct c3_isp_rsz_format_info *rsz_fmt; 598 599 src_fmt = v4l2_subdev_state_get_format(state, format->pad); 600 sink_fmt = v4l2_subdev_state_get_format(state, C3_ISP_RSZ_PAD_SINK); 601 sink_cmps = v4l2_subdev_state_get_compose(state, C3_ISP_RSZ_PAD_SINK); 602 603 src_fmt->code = sink_fmt->code; 604 src_fmt->width = sink_cmps->width; 605 src_fmt->height = sink_cmps->height; 606 src_fmt->field = V4L2_FIELD_NONE; 607 src_fmt->ycbcr_enc = V4L2_YCBCR_ENC_601; 608 609 rsz_fmt = rsz_find_format_by_code(src_fmt->code, format->pad); 610 if (rsz_fmt->is_raw) { 611 src_fmt->colorspace = V4L2_COLORSPACE_RAW; 612 src_fmt->xfer_func = V4L2_XFER_FUNC_NONE; 613 src_fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE; 614 } else { 615 src_fmt->colorspace = V4L2_COLORSPACE_SRGB; 616 src_fmt->xfer_func = V4L2_XFER_FUNC_SRGB; 617 src_fmt->quantization = V4L2_QUANTIZATION_LIM_RANGE; 618 } 619 620 format->format = *src_fmt; 621} 622 623static int c3_isp_rsz_set_fmt(struct v4l2_subdev *sd, 624 struct v4l2_subdev_state *state, 625 struct v4l2_subdev_format *format) 626{ 627 if (format->pad == C3_ISP_RSZ_PAD_SINK) 628 c3_isp_rsz_set_sink_fmt(state, format); 629 else 630 c3_isp_rsz_set_source_fmt(state, format); 631 632 return 0; 633} 634 635static int c3_isp_rsz_get_selection(struct v4l2_subdev *sd, 636 struct v4l2_subdev_state *state, 637 struct v4l2_subdev_selection *sel) 638{ 639 struct v4l2_mbus_framefmt *fmt; 640 struct v4l2_rect *crop; 641 struct v4l2_rect *cmps; 642 643 if (sel->pad == C3_ISP_RSZ_PAD_SOURCE) 644 return -EINVAL; 645 646 switch (sel->target) { 647 case V4L2_SEL_TGT_CROP_BOUNDS: 648 fmt = v4l2_subdev_state_get_format(state, sel->pad); 649 sel->r.width = fmt->width; 650 sel->r.height = fmt->height; 651 sel->r.left = 0; 652 sel->r.top = 0; 653 break; 654 case V4L2_SEL_TGT_COMPOSE_BOUNDS: 655 crop = v4l2_subdev_state_get_crop(state, sel->pad); 656 sel->r.width = crop->width; 657 sel->r.height = crop->height; 658 sel->r.left = 0; 659 sel->r.top = 0; 660 break; 661 case V4L2_SEL_TGT_CROP: 662 crop = v4l2_subdev_state_get_crop(state, sel->pad); 663 sel->r = *crop; 664 break; 665 case V4L2_SEL_TGT_COMPOSE: 666 cmps = v4l2_subdev_state_get_compose(state, sel->pad); 667 sel->r = *cmps; 668 break; 669 default: 670 return -EINVAL; 671 } 672 673 return 0; 674} 675 676static int c3_isp_rsz_set_selection(struct v4l2_subdev *sd, 677 struct v4l2_subdev_state *state, 678 struct v4l2_subdev_selection *sel) 679{ 680 struct v4l2_mbus_framefmt *fmt; 681 struct v4l2_mbus_framefmt *src_fmt; 682 struct v4l2_rect *crop; 683 struct v4l2_rect *cmps; 684 685 if (sel->pad == C3_ISP_RSZ_PAD_SOURCE) 686 return -EINVAL; 687 688 switch (sel->target) { 689 case V4L2_SEL_TGT_CROP: 690 fmt = v4l2_subdev_state_get_format(state, sel->pad); 691 crop = v4l2_subdev_state_get_crop(state, sel->pad); 692 cmps = v4l2_subdev_state_get_compose(state, sel->pad); 693 src_fmt = v4l2_subdev_state_get_format(state, 694 C3_ISP_RSZ_PAD_SOURCE); 695 696 sel->r.left = clamp_t(s32, sel->r.left, 0, fmt->width - 1); 697 sel->r.top = clamp_t(s32, sel->r.top, 0, fmt->height - 1); 698 sel->r.width = clamp(sel->r.width, C3_ISP_MIN_WIDTH, 699 fmt->width - sel->r.left); 700 sel->r.height = clamp(sel->r.height, C3_ISP_MIN_HEIGHT, 701 fmt->height - sel->r.top); 702 703 crop->width = ALIGN(sel->r.width, 2); 704 crop->height = ALIGN(sel->r.height, 2); 705 crop->left = sel->r.left; 706 crop->top = sel->r.top; 707 708 *cmps = *crop; 709 710 src_fmt->code = fmt->code; 711 src_fmt->width = cmps->width; 712 src_fmt->height = cmps->height; 713 714 sel->r = *crop; 715 break; 716 case V4L2_SEL_TGT_COMPOSE: 717 crop = v4l2_subdev_state_get_crop(state, sel->pad); 718 cmps = v4l2_subdev_state_get_compose(state, sel->pad); 719 720 sel->r.left = 0; 721 sel->r.top = 0; 722 sel->r.width = clamp(sel->r.width, C3_ISP_MIN_WIDTH, 723 crop->width); 724 sel->r.height = clamp(sel->r.height, C3_ISP_MIN_HEIGHT, 725 crop->height); 726 727 cmps->width = ALIGN(sel->r.width, 2); 728 cmps->height = ALIGN(sel->r.height, 2); 729 cmps->left = sel->r.left; 730 cmps->top = sel->r.top; 731 732 sel->r = *cmps; 733 734 fmt = v4l2_subdev_state_get_format(state, 735 C3_ISP_RSZ_PAD_SOURCE); 736 fmt->width = cmps->width; 737 fmt->height = cmps->height; 738 break; 739 default: 740 return -EINVAL; 741 } 742 743 return 0; 744} 745 746static int c3_isp_rsz_init_state(struct v4l2_subdev *sd, 747 struct v4l2_subdev_state *state) 748{ 749 struct v4l2_mbus_framefmt *fmt; 750 struct v4l2_rect *crop; 751 struct v4l2_rect *cmps; 752 753 fmt = v4l2_subdev_state_get_format(state, C3_ISP_RSZ_PAD_SINK); 754 fmt->width = C3_ISP_DEFAULT_WIDTH; 755 fmt->height = C3_ISP_DEFAULT_HEIGHT; 756 fmt->field = V4L2_FIELD_NONE; 757 fmt->code = C3_ISP_RSZ_DEF_PAD_FMT; 758 fmt->colorspace = V4L2_COLORSPACE_SRGB; 759 fmt->xfer_func = V4L2_XFER_FUNC_SRGB; 760 fmt->ycbcr_enc = V4L2_YCBCR_ENC_601; 761 fmt->quantization = V4L2_QUANTIZATION_LIM_RANGE; 762 763 crop = v4l2_subdev_state_get_crop(state, C3_ISP_RSZ_PAD_SINK); 764 crop->width = C3_ISP_DEFAULT_WIDTH; 765 crop->height = C3_ISP_DEFAULT_HEIGHT; 766 crop->left = 0; 767 crop->top = 0; 768 769 cmps = v4l2_subdev_state_get_compose(state, C3_ISP_RSZ_PAD_SINK); 770 cmps->width = C3_ISP_DEFAULT_WIDTH; 771 cmps->height = C3_ISP_DEFAULT_HEIGHT; 772 cmps->left = 0; 773 cmps->top = 0; 774 775 fmt = v4l2_subdev_state_get_format(state, C3_ISP_RSZ_PAD_SOURCE); 776 fmt->width = cmps->width; 777 fmt->height = cmps->height; 778 fmt->field = V4L2_FIELD_NONE; 779 fmt->code = C3_ISP_RSZ_DEF_PAD_FMT; 780 fmt->colorspace = V4L2_COLORSPACE_SRGB; 781 fmt->xfer_func = V4L2_XFER_FUNC_SRGB; 782 fmt->ycbcr_enc = V4L2_YCBCR_ENC_601; 783 fmt->quantization = V4L2_QUANTIZATION_LIM_RANGE; 784 785 return 0; 786} 787 788static const struct v4l2_subdev_pad_ops c3_isp_rsz_pad_ops = { 789 .enum_mbus_code = c3_isp_rsz_enum_mbus_code, 790 .get_fmt = v4l2_subdev_get_fmt, 791 .set_fmt = c3_isp_rsz_set_fmt, 792 .get_selection = c3_isp_rsz_get_selection, 793 .set_selection = c3_isp_rsz_set_selection, 794 .enable_streams = c3_isp_rsz_enable_streams, 795 .disable_streams = c3_isp_rsz_disable_streams, 796}; 797 798static const struct v4l2_subdev_ops c3_isp_rsz_subdev_ops = { 799 .pad = &c3_isp_rsz_pad_ops, 800}; 801 802static const struct v4l2_subdev_internal_ops c3_isp_rsz_internal_ops = { 803 .init_state = c3_isp_rsz_init_state, 804}; 805 806/* Media entity operations */ 807static const struct media_entity_operations c3_isp_rsz_entity_ops = { 808 .link_validate = v4l2_subdev_link_validate, 809}; 810 811static int c3_isp_rsz_register(struct c3_isp_resizer *rsz) 812{ 813 struct v4l2_subdev *sd = &rsz->sd; 814 int ret; 815 816 v4l2_subdev_init(sd, &c3_isp_rsz_subdev_ops); 817 sd->owner = THIS_MODULE; 818 sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; 819 sd->internal_ops = &c3_isp_rsz_internal_ops; 820 snprintf(sd->name, sizeof(sd->name), "c3-isp-resizer%u", rsz->id); 821 822 sd->entity.function = MEDIA_ENT_F_PROC_VIDEO_SCALER; 823 sd->entity.ops = &c3_isp_rsz_entity_ops; 824 825 sd->dev = rsz->isp->dev; 826 v4l2_set_subdevdata(sd, rsz); 827 828 rsz->pads[C3_ISP_RSZ_PAD_SINK].flags = MEDIA_PAD_FL_SINK; 829 rsz->pads[C3_ISP_RSZ_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; 830 ret = media_entity_pads_init(&sd->entity, C3_ISP_RSZ_PAD_MAX, 831 rsz->pads); 832 if (ret) 833 return ret; 834 835 ret = v4l2_subdev_init_finalize(sd); 836 if (ret) 837 goto err_entity_cleanup; 838 839 ret = v4l2_device_register_subdev(&rsz->isp->v4l2_dev, sd); 840 if (ret) 841 goto err_subdev_cleanup; 842 843 return 0; 844 845err_subdev_cleanup: 846 v4l2_subdev_cleanup(sd); 847err_entity_cleanup: 848 media_entity_cleanup(&sd->entity); 849 return ret; 850} 851 852static void c3_isp_rsz_unregister(struct c3_isp_resizer *rsz) 853{ 854 struct v4l2_subdev *sd = &rsz->sd; 855 856 v4l2_device_unregister_subdev(sd); 857 v4l2_subdev_cleanup(sd); 858 media_entity_cleanup(&sd->entity); 859} 860 861int c3_isp_resizers_register(struct c3_isp_device *isp) 862{ 863 int ret; 864 865 for (unsigned int i = C3_ISP_RSZ_0; i < C3_ISP_NUM_RSZ; i++) { 866 struct c3_isp_resizer *rsz = &isp->resizers[i]; 867 868 rsz->id = i; 869 rsz->isp = isp; 870 rsz->src_sd = &isp->core.sd; 871 rsz->src_pad = C3_ISP_CORE_PAD_SOURCE_VIDEO_0 + i; 872 873 ret = c3_isp_rsz_register(rsz); 874 if (ret) { 875 rsz->isp = NULL; 876 c3_isp_resizers_unregister(isp); 877 return ret; 878 } 879 } 880 881 return 0; 882} 883 884void c3_isp_resizers_unregister(struct c3_isp_device *isp) 885{ 886 for (unsigned int i = C3_ISP_RSZ_0; i < C3_ISP_NUM_RSZ; i++) { 887 struct c3_isp_resizer *rsz = &isp->resizers[i]; 888 889 if (rsz->isp) 890 c3_isp_rsz_unregister(rsz); 891 } 892}
~/
Read-only file preview.