1/* 2 * Copyright (C) 2012 Texas Instruments Inc 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License as 6 * published by the Free Software Foundation version 2. 7 * 8 * This program is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * GNU General Public License for more details. 12 * 13 * You should have received a copy of the GNU General Public License 14 * along with this program; if not, write to the Free Software 15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 16 * 17 * Contributors: 18 * Manjunath Hadli <manjunath.hadli@ti.com> 19 * Prabhakar Lad <prabhakar.lad@ti.com> 20 * 21 * 22 * Resizer allows upscaling or downscaling a image to a desired 23 * resolution. There are 2 resizer modules. both operating on the 24 * same input image, but can have different output resolution. 25 */ 26 27#include "dm365_ipipe_hw.h" 28#include "dm365_resizer.h" 29 30#define MIN_IN_WIDTH 32 31#define MIN_IN_HEIGHT 32 32#define MAX_IN_WIDTH 4095 33#define MAX_IN_HEIGHT 4095 34#define MIN_OUT_WIDTH 16 35#define MIN_OUT_HEIGHT 2 36 37static const unsigned int resizer_input_formats[] = { 38 V4L2_MBUS_FMT_UYVY8_2X8, 39 V4L2_MBUS_FMT_Y8_1X8, 40 V4L2_MBUS_FMT_UV8_1X8, 41 V4L2_MBUS_FMT_SGRBG12_1X12, 42}; 43 44static const unsigned int resizer_output_formats[] = { 45 V4L2_MBUS_FMT_UYVY8_2X8, 46 V4L2_MBUS_FMT_Y8_1X8, 47 V4L2_MBUS_FMT_UV8_1X8, 48 V4L2_MBUS_FMT_YDYUYDYV8_1X16, 49 V4L2_MBUS_FMT_SGRBG12_1X12, 50}; 51 52/* resizer_calculate_line_length() - This function calculates the line length of 53 * various image planes at the input and 54 * output. 55 */ 56static void 57resizer_calculate_line_length(enum v4l2_mbus_pixelcode pix, int width, 58 int height, int *line_len, int *line_len_c) 59{ 60 *line_len = 0; 61 *line_len_c = 0; 62 63 if (pix == V4L2_MBUS_FMT_UYVY8_2X8 || 64 pix == V4L2_MBUS_FMT_SGRBG12_1X12) { 65 *line_len = width << 1; 66 } else if (pix == V4L2_MBUS_FMT_Y8_1X8 || 67 pix == V4L2_MBUS_FMT_UV8_1X8) { 68 *line_len = width; 69 *line_len_c = width; 70 } else { 71 /* YUV 420 */ 72 /* round width to upper 32 byte boundary */ 73 *line_len = width; 74 *line_len_c = width; 75 } 76 /* adjust the line len to be a multiple of 32 */ 77 *line_len += 31; 78 *line_len &= ~0x1f; 79 *line_len_c += 31; 80 *line_len_c &= ~0x1f; 81} 82 83static inline int 84resizer_validate_output_image_format(struct device *dev, 85 struct v4l2_mbus_framefmt *format, 86 int *in_line_len, int *in_line_len_c) 87{ 88 if (format->code != V4L2_MBUS_FMT_UYVY8_2X8 && 89 format->code != V4L2_MBUS_FMT_Y8_1X8 && 90 format->code != V4L2_MBUS_FMT_UV8_1X8 && 91 format->code != V4L2_MBUS_FMT_YDYUYDYV8_1X16 && 92 format->code != V4L2_MBUS_FMT_SGRBG12_1X12) { 93 dev_err(dev, "Invalid Mbus format, %d\n", format->code); 94 return -EINVAL; 95 } 96 if (!format->width || !format->height) { 97 dev_err(dev, "invalid width or height\n"); 98 return -EINVAL; 99 } 100 resizer_calculate_line_length(format->code, format->width, 101 format->height, in_line_len, in_line_len_c); 102 return 0; 103} 104 105static void 106resizer_configure_passthru(struct vpfe_resizer_device *resizer, int bypass) 107{ 108 struct resizer_params *param = &resizer->config; 109 110 param->rsz_rsc_param[RSZ_A].cen = DISABLE; 111 param->rsz_rsc_param[RSZ_A].yen = DISABLE; 112 param->rsz_rsc_param[RSZ_A].v_phs_y = 0; 113 param->rsz_rsc_param[RSZ_A].v_phs_c = 0; 114 param->rsz_rsc_param[RSZ_A].v_dif = 256; 115 param->rsz_rsc_param[RSZ_A].v_lpf_int_y = 0; 116 param->rsz_rsc_param[RSZ_A].v_lpf_int_c = 0; 117 param->rsz_rsc_param[RSZ_A].h_phs = 0; 118 param->rsz_rsc_param[RSZ_A].h_dif = 256; 119 param->rsz_rsc_param[RSZ_A].h_lpf_int_y = 0; 120 param->rsz_rsc_param[RSZ_A].h_lpf_int_c = 0; 121 param->rsz_rsc_param[RSZ_A].dscale_en = DISABLE; 122 param->rsz2rgb[RSZ_A].rgb_en = DISABLE; 123 param->rsz_en[RSZ_A] = ENABLE; 124 param->rsz_en[RSZ_B] = DISABLE; 125 if (bypass) { 126 param->rsz_rsc_param[RSZ_A].i_vps = 0; 127 param->rsz_rsc_param[RSZ_A].i_hps = 0; 128 /* Raw Bypass */ 129 param->rsz_common.passthrough = BYPASS_ON; 130 } 131} 132 133static void 134configure_resizer_out_params(struct vpfe_resizer_device *resizer, int index, 135 void *output_spec, unsigned char partial, 136 unsigned flag) 137{ 138 struct resizer_params *param = &resizer->config; 139 struct v4l2_mbus_framefmt *outformat; 140 struct vpfe_rsz_output_spec *output; 141 142 if (index == RSZ_A && 143 resizer->resizer_a.output == RESIZER_OUTPUT_NONE) { 144 param->rsz_en[index] = DISABLE; 145 return; 146 } 147 if (index == RSZ_B && 148 resizer->resizer_b.output == RESIZER_OUTPUT_NONE) { 149 param->rsz_en[index] = DISABLE; 150 return; 151 } 152 output = (struct vpfe_rsz_output_spec *)output_spec; 153 param->rsz_en[index] = ENABLE; 154 if (partial) { 155 param->rsz_rsc_param[index].h_flip = output->h_flip; 156 param->rsz_rsc_param[index].v_flip = output->v_flip; 157 param->rsz_rsc_param[index].v_typ_y = output->v_typ_y; 158 param->rsz_rsc_param[index].v_typ_c = output->v_typ_c; 159 param->rsz_rsc_param[index].v_lpf_int_y = 160 output->v_lpf_int_y; 161 param->rsz_rsc_param[index].v_lpf_int_c = 162 output->v_lpf_int_c; 163 param->rsz_rsc_param[index].h_typ_y = output->h_typ_y; 164 param->rsz_rsc_param[index].h_typ_c = output->h_typ_c; 165 param->rsz_rsc_param[index].h_lpf_int_y = 166 output->h_lpf_int_y; 167 param->rsz_rsc_param[index].h_lpf_int_c = 168 output->h_lpf_int_c; 169 param->rsz_rsc_param[index].dscale_en = 170 output->en_down_scale; 171 param->rsz_rsc_param[index].h_dscale_ave_sz = 172 output->h_dscale_ave_sz; 173 param->rsz_rsc_param[index].v_dscale_ave_sz = 174 output->v_dscale_ave_sz; 175 param->ext_mem_param[index].user_y_ofst = 176 (output->user_y_ofst + 31) & ~0x1f; 177 param->ext_mem_param[index].user_c_ofst = 178 (output->user_c_ofst + 31) & ~0x1f; 179 return; 180 } 181 182 if (index == RSZ_A) 183 outformat = &resizer->resizer_a.formats[RESIZER_PAD_SOURCE]; 184 else 185 outformat = &resizer->resizer_b.formats[RESIZER_PAD_SOURCE]; 186 param->rsz_rsc_param[index].o_vsz = outformat->height - 1; 187 param->rsz_rsc_param[index].o_hsz = outformat->width - 1; 188 param->ext_mem_param[index].rsz_sdr_ptr_s_y = output->vst_y; 189 param->ext_mem_param[index].rsz_sdr_ptr_e_y = outformat->height; 190 param->ext_mem_param[index].rsz_sdr_ptr_s_c = output->vst_c; 191 param->ext_mem_param[index].rsz_sdr_ptr_e_c = outformat->height; 192 193 if (!flag) 194 return; 195 /* update common parameters */ 196 param->rsz_rsc_param[index].h_flip = output->h_flip; 197 param->rsz_rsc_param[index].v_flip = output->v_flip; 198 param->rsz_rsc_param[index].v_typ_y = output->v_typ_y; 199 param->rsz_rsc_param[index].v_typ_c = output->v_typ_c; 200 param->rsz_rsc_param[index].v_lpf_int_y = output->v_lpf_int_y; 201 param->rsz_rsc_param[index].v_lpf_int_c = output->v_lpf_int_c; 202 param->rsz_rsc_param[index].h_typ_y = output->h_typ_y; 203 param->rsz_rsc_param[index].h_typ_c = output->h_typ_c; 204 param->rsz_rsc_param[index].h_lpf_int_y = output->h_lpf_int_y; 205 param->rsz_rsc_param[index].h_lpf_int_c = output->h_lpf_int_c; 206 param->rsz_rsc_param[index].dscale_en = output->en_down_scale; 207 param->rsz_rsc_param[index].h_dscale_ave_sz = output->h_dscale_ave_sz; 208 param->rsz_rsc_param[index].v_dscale_ave_sz = output->h_dscale_ave_sz; 209 param->ext_mem_param[index].user_y_ofst = 210 (output->user_y_ofst + 31) & ~0x1f; 211 param->ext_mem_param[index].user_c_ofst = 212 (output->user_c_ofst + 31) & ~0x1f; 213} 214 215/* 216 * resizer_calculate_resize_ratios() - Calculates resize ratio for resizer 217 * A or B. This is called after setting 218 * the input size or output size. 219 * @resizer: Pointer to VPFE resizer subdevice. 220 * @index: index RSZ_A-resizer-A RSZ_B-resizer-B. 221 */ 222static void 223resizer_calculate_resize_ratios(struct vpfe_resizer_device *resizer, int index) 224{ 225 struct resizer_params *param = &resizer->config; 226 struct v4l2_mbus_framefmt *informat, *outformat; 227 228 informat = &resizer->crop_resizer.formats[RESIZER_CROP_PAD_SINK]; 229 230 if (index == RSZ_A) 231 outformat = &resizer->resizer_a.formats[RESIZER_PAD_SOURCE]; 232 else 233 outformat = &resizer->resizer_b.formats[RESIZER_PAD_SOURCE]; 234 235 if (outformat->field != V4L2_FIELD_INTERLACED) 236 param->rsz_rsc_param[index].v_dif = 237 ((informat->height) * 256) / (outformat->height); 238 else 239 param->rsz_rsc_param[index].v_dif = 240 ((informat->height >> 1) * 256) / (outformat->height); 241 param->rsz_rsc_param[index].h_dif = 242 ((informat->width) * 256) / (outformat->width); 243} 244 245void 246static resizer_enable_422_420_conversion(struct resizer_params *param, 247 int index, bool en) 248{ 249 param->rsz_rsc_param[index].cen = en; 250 param->rsz_rsc_param[index].yen = en; 251} 252 253/* resizer_calculate_sdram_offsets() - This function calculates the offsets from 254 * start of buffer for the C plane when 255 * output format is YUV420SP. It also 256 * calculates the offsets from the start of 257 * the buffer when the image is flipped 258 * vertically or horizontally for ycbcr/y/c 259 * planes. 260 * @resizer: Pointer to resizer subdevice. 261 * @index: index RSZ_A-resizer-A RSZ_B-resizer-B. 262 */ 263static int 264resizer_calculate_sdram_offsets(struct vpfe_resizer_device *resizer, int index) 265{ 266 struct resizer_params *param = &resizer->config; 267 struct v4l2_mbus_framefmt *outformat; 268 int bytesperpixel = 2; 269 int image_height; 270 int image_width; 271 int yuv_420 = 0; 272 int offset = 0; 273 274 if (index == RSZ_A) 275 outformat = &resizer->resizer_a.formats[RESIZER_PAD_SOURCE]; 276 else 277 outformat = &resizer->resizer_b.formats[RESIZER_PAD_SOURCE]; 278 279 image_height = outformat->height + 1; 280 image_width = outformat->width + 1; 281 param->ext_mem_param[index].c_offset = 0; 282 param->ext_mem_param[index].flip_ofst_y = 0; 283 param->ext_mem_param[index].flip_ofst_c = 0; 284 if (outformat->code == V4L2_MBUS_FMT_YDYUYDYV8_1X16) { 285 /* YUV 420 */ 286 yuv_420 = 1; 287 bytesperpixel = 1; 288 } 289 290 if (param->rsz_rsc_param[index].h_flip) 291 /* width * bytesperpixel - 1 */ 292 offset = (image_width * bytesperpixel) - 1; 293 if (param->rsz_rsc_param[index].v_flip) 294 offset += (image_height - 1) * 295 param->ext_mem_param[index].rsz_sdr_oft_y; 296 param->ext_mem_param[index].flip_ofst_y = offset; 297 if (!yuv_420) 298 return 0; 299 offset = 0; 300 /* half height for c-plane */ 301 if (param->rsz_rsc_param[index].h_flip) 302 /* width * bytesperpixel - 1 */ 303 offset = image_width - 1; 304 if (param->rsz_rsc_param[index].v_flip) 305 offset += (((image_height >> 1) - 1) * 306 param->ext_mem_param[index].rsz_sdr_oft_c); 307 param->ext_mem_param[index].flip_ofst_c = offset; 308 param->ext_mem_param[index].c_offset = 309 param->ext_mem_param[index].rsz_sdr_oft_y * image_height; 310 return 0; 311} 312 313static int resizer_configure_output_win(struct vpfe_resizer_device *resizer) 314{ 315 struct resizer_params *param = &resizer->config; 316 struct vpfe_rsz_output_spec output_specs; 317 struct v4l2_mbus_framefmt *outformat; 318 int line_len_c; 319 int line_len; 320 int ret; 321 322 outformat = &resizer->resizer_a.formats[RESIZER_PAD_SOURCE]; 323 324 output_specs.vst_y = param->user_config.vst; 325 if (outformat->code == V4L2_MBUS_FMT_YDYUYDYV8_1X16) 326 output_specs.vst_c = param->user_config.vst; 327 328 configure_resizer_out_params(resizer, RSZ_A, &output_specs, 0, 0); 329 resizer_calculate_line_length(outformat->code, 330 param->rsz_rsc_param[0].o_hsz + 1, 331 param->rsz_rsc_param[0].o_vsz + 1, 332 &line_len, &line_len_c); 333 param->ext_mem_param[0].rsz_sdr_oft_y = line_len; 334 param->ext_mem_param[0].rsz_sdr_oft_c = line_len_c; 335 resizer_calculate_resize_ratios(resizer, RSZ_A); 336 if (param->rsz_en[RSZ_B]) 337 resizer_calculate_resize_ratios(resizer, RSZ_B); 338 339 if (outformat->code == V4L2_MBUS_FMT_YDYUYDYV8_1X16) 340 resizer_enable_422_420_conversion(param, RSZ_A, ENABLE); 341 else 342 resizer_enable_422_420_conversion(param, RSZ_A, DISABLE); 343 344 ret = resizer_calculate_sdram_offsets(resizer, RSZ_A); 345 if (!ret && param->rsz_en[RSZ_B]) 346 ret = resizer_calculate_sdram_offsets(resizer, RSZ_B); 347 348 if (ret) 349 pr_err("Error in calculating sdram offsets\n"); 350 return ret; 351} 352 353static int 354resizer_calculate_down_scale_f_div_param(struct device *dev, 355 int input_width, int output_width, 356 struct resizer_scale_param *param) 357{ 358 /* rsz = R, input_width = H, output width = h in the equation */ 359 unsigned int two_power; 360 unsigned int upper_h1; 361 unsigned int upper_h2; 362 unsigned int val1; 363 unsigned int val; 364 unsigned int rsz; 365 unsigned int h1; 366 unsigned int h2; 367 unsigned int o; 368 unsigned int n; 369 370 upper_h1 = input_width >> 1; 371 n = param->h_dscale_ave_sz; 372 /* 2 ^ (scale+1) */ 373 two_power = 1 << (n + 1); 374 upper_h1 = (upper_h1 >> (n + 1)) << (n + 1); 375 upper_h2 = input_width - upper_h1; 376 if (upper_h2 % two_power) { 377 dev_err(dev, "frame halves to be a multiple of 2 power n+1\n"); 378 return -EINVAL; 379 } 380 two_power = 1 << n; 381 rsz = (input_width << 8) / output_width; 382 val = rsz * two_power; 383 val = ((upper_h1 << 8) / val) + 1; 384 if (!(val % 2)) { 385 h1 = val; 386 } else { 387 val = upper_h1 << 8; 388 val >>= n + 1; 389 val -= rsz >> 1; 390 val /= rsz << 1; 391 val <<= 1; 392 val += 2; 393 h1 = val; 394 } 395 o = 10 + (two_power << 2); 396 if (((input_width << 7) / rsz) % 2) 397 o += (((CEIL(rsz, 1024)) << 1) << n); 398 h2 = output_width - h1; 399 /* phi */ 400 val = (h1 * rsz) - (((upper_h1 - (o - 10)) / two_power) << 8); 401 /* skip */ 402 val1 = ((val - 1024) >> 9) << 1; 403 param->f_div.num_passes = MAX_PASSES; 404 param->f_div.pass[0].o_hsz = h1 - 1; 405 param->f_div.pass[0].i_hps = 0; 406 param->f_div.pass[0].h_phs = 0; 407 param->f_div.pass[0].src_hps = 0; 408 param->f_div.pass[0].src_hsz = upper_h1 + o; 409 param->f_div.pass[1].o_hsz = h2 - 1; 410 param->f_div.pass[1].i_hps = 10 + (val1 * two_power); 411 param->f_div.pass[1].h_phs = (val - (val1 << 8)); 412 param->f_div.pass[1].src_hps = upper_h1 - o; 413 param->f_div.pass[1].src_hsz = upper_h2 + o; 414 415 return 0; 416} 417 418static int 419resizer_configure_common_in_params(struct vpfe_resizer_device *resizer) 420{ 421 struct vpfe_device *vpfe_dev = to_vpfe_device(resizer); 422 struct resizer_params *param = &resizer->config; 423 struct vpfe_rsz_config_params *user_config; 424 struct v4l2_mbus_framefmt *informat; 425 426 informat = &resizer->crop_resizer.formats[RESIZER_CROP_PAD_SINK]; 427 user_config = &resizer->config.user_config; 428 param->rsz_common.vps = param->user_config.vst; 429 param->rsz_common.hps = param->user_config.hst; 430 431 if (vpfe_ipipeif_decimation_enabled(vpfe_dev)) 432 param->rsz_common.hsz = (((informat->width - 1) * 433 IPIPEIF_RSZ_CONST) / vpfe_ipipeif_get_rsz(vpfe_dev)); 434 else 435 param->rsz_common.hsz = informat->width - 1; 436 437 if (informat->field == V4L2_FIELD_INTERLACED) 438 param->rsz_common.vsz = (informat->height - 1) >> 1; 439 else 440 param->rsz_common.vsz = informat->height - 1; 441 442 param->rsz_common.raw_flip = 0; 443 444 if (resizer->crop_resizer.input == RESIZER_CROP_INPUT_IPIPEIF) 445 param->rsz_common.source = IPIPEIF_DATA; 446 else 447 param->rsz_common.source = IPIPE_DATA; 448 449 switch (informat->code) { 450 case V4L2_MBUS_FMT_UYVY8_2X8: 451 param->rsz_common.src_img_fmt = RSZ_IMG_422; 452 param->rsz_common.raw_flip = 0; 453 break; 454 455 case V4L2_MBUS_FMT_Y8_1X8: 456 param->rsz_common.src_img_fmt = RSZ_IMG_420; 457 /* Select y */ 458 param->rsz_common.y_c = 0; 459 param->rsz_common.raw_flip = 0; 460 break; 461 462 case V4L2_MBUS_FMT_UV8_1X8: 463 param->rsz_common.src_img_fmt = RSZ_IMG_420; 464 /* Select y */ 465 param->rsz_common.y_c = 1; 466 param->rsz_common.raw_flip = 0; 467 break; 468 469 case V4L2_MBUS_FMT_SGRBG12_1X12: 470 param->rsz_common.raw_flip = 1; 471 break; 472 473 default: 474 param->rsz_common.src_img_fmt = RSZ_IMG_422; 475 param->rsz_common.source = IPIPE_DATA; 476 } 477 478 param->rsz_common.yuv_y_min = user_config->yuv_y_min; 479 param->rsz_common.yuv_y_max = user_config->yuv_y_max; 480 param->rsz_common.yuv_c_min = user_config->yuv_c_min; 481 param->rsz_common.yuv_c_max = user_config->yuv_c_max; 482 param->rsz_common.out_chr_pos = user_config->out_chr_pos; 483 param->rsz_common.rsz_seq_crv = user_config->chroma_sample_even; 484 485 return 0; 486} 487static int 488resizer_configure_in_continious_mode(struct vpfe_resizer_device *resizer) 489{ 490 struct device *dev = resizer->crop_resizer.subdev.v4l2_dev->dev; 491 struct resizer_params *param = &resizer->config; 492 struct vpfe_rsz_config_params *cont_config; 493 int line_len_c; 494 int line_len; 495 int ret; 496 497 if (resizer->resizer_a.output != RESIZER_OUPUT_MEMORY) { 498 dev_err(dev, "enable resizer - Resizer-A\n"); 499 return -EINVAL; 500 } 501 502 cont_config = &resizer->config.user_config; 503 param->rsz_en[RSZ_A] = ENABLE; 504 configure_resizer_out_params(resizer, RSZ_A, 505 &cont_config->output1, 1, 0); 506 param->rsz_en[RSZ_B] = DISABLE; 507 param->oper_mode = RESIZER_MODE_CONTINIOUS; 508 509 if (resizer->resizer_b.output == RESIZER_OUPUT_MEMORY) { 510 struct v4l2_mbus_framefmt *outformat2; 511 512 param->rsz_en[RSZ_B] = ENABLE; 513 outformat2 = &resizer->resizer_b.formats[RESIZER_PAD_SOURCE]; 514 ret = resizer_validate_output_image_format(dev, outformat2, 515 &line_len, &line_len_c); 516 if (ret) 517 return ret; 518 param->ext_mem_param[RSZ_B].rsz_sdr_oft_y = line_len; 519 param->ext_mem_param[RSZ_B].rsz_sdr_oft_c = line_len_c; 520 configure_resizer_out_params(resizer, RSZ_B, 521 &cont_config->output2, 0, 1); 522 if (outformat2->code == V4L2_MBUS_FMT_YDYUYDYV8_1X16) 523 resizer_enable_422_420_conversion(param, 524 RSZ_B, ENABLE); 525 else 526 resizer_enable_422_420_conversion(param, 527 RSZ_B, DISABLE); 528 } 529 resizer_configure_common_in_params(resizer); 530 ret = resizer_configure_output_win(resizer); 531 if (ret) 532 return ret; 533 534 param->rsz_common.passthrough = cont_config->bypass; 535 if (cont_config->bypass) 536 resizer_configure_passthru(resizer, 1); 537 538 return 0; 539} 540 541static inline int 542resizer_validate_input_image_format(struct device *dev, 543 enum v4l2_mbus_pixelcode pix, 544 int width, int height, int *line_len) 545{ 546 int val; 547 548 if (pix != V4L2_MBUS_FMT_UYVY8_2X8 && 549 pix != V4L2_MBUS_FMT_Y8_1X8 && 550 pix != V4L2_MBUS_FMT_UV8_1X8 && 551 pix != V4L2_MBUS_FMT_SGRBG12_1X12) { 552 dev_err(dev, 553 "resizer validate output: pix format not supported, %d\n", pix); 554 return -EINVAL; 555 } 556 557 if (!width || !height) { 558 dev_err(dev, 559 "resizer validate input: invalid width or height\n"); 560 return -EINVAL; 561 } 562 563 if (pix == V4L2_MBUS_FMT_UV8_1X8) 564 resizer_calculate_line_length(pix, width, 565 height, &val, line_len); 566 else 567 resizer_calculate_line_length(pix, width, 568 height, line_len, &val); 569 570 return 0; 571} 572 573static int 574resizer_validate_decimation(struct device *dev, enum ipipeif_decimation dec_en, 575 unsigned char rsz, unsigned char frame_div_mode_en, 576 int width) 577{ 578 if (dec_en && frame_div_mode_en) { 579 dev_err(dev, 580 "dec_en & frame_div_mode_en can not enabled simultaneously\n"); 581 return -EINVAL; 582 } 583 584 if (frame_div_mode_en) { 585 dev_err(dev, "frame_div_mode mode not supported\n"); 586 return -EINVAL; 587 } 588 589 if (!dec_en) 590 return 0; 591 592 if (width <= VPFE_IPIPE_MAX_INPUT_WIDTH) { 593 dev_err(dev, 594 "image width to be more than %d for decimation\n", 595 VPFE_IPIPE_MAX_INPUT_WIDTH); 596 return -EINVAL; 597 } 598 599 if (rsz < IPIPEIF_RSZ_MIN || rsz > IPIPEIF_RSZ_MAX) { 600 dev_err(dev, "rsz range is %d to %d\n", 601 IPIPEIF_RSZ_MIN, IPIPEIF_RSZ_MAX); 602 return -EINVAL; 603 } 604 605 return 0; 606} 607 608/* resizer_calculate_normal_f_div_param() - Algorithm to calculate the frame 609 * division parameters for resizer. 610 * in normal mode. 611 */ 612static int 613resizer_calculate_normal_f_div_param(struct device *dev, int input_width, 614 int output_width, struct resizer_scale_param *param) 615{ 616 /* rsz = R, input_width = H, output width = h in the equation */ 617 unsigned int val1; 618 unsigned int rsz; 619 unsigned int val; 620 unsigned int h1; 621 unsigned int h2; 622 unsigned int o; 623 624 if (output_width > input_width) { 625 dev_err(dev, "frame div mode is used for scale down only\n"); 626 return -EINVAL; 627 } 628 629 rsz = (input_width << 8) / output_width; 630 val = rsz << 1; 631 val = ((input_width << 8) / val) + 1; 632 o = 14; 633 if (!(val % 2)) { 634 h1 = val; 635 } else { 636 val = (input_width << 7); 637 val -= rsz >> 1; 638 val /= rsz << 1; 639 val <<= 1; 640 val += 2; 641 o += ((CEIL(rsz, 1024)) << 1); 642 h1 = val; 643 } 644 h2 = output_width - h1; 645 /* phi */ 646 val = (h1 * rsz) - (((input_width >> 1) - o) << 8); 647 /* skip */ 648 val1 = ((val - 1024) >> 9) << 1; 649 param->f_div.num_passes = MAX_PASSES; 650 param->f_div.pass[0].o_hsz = h1 - 1; 651 param->f_div.pass[0].i_hps = 0; 652 param->f_div.pass[0].h_phs = 0; 653 param->f_div.pass[0].src_hps = 0; 654 param->f_div.pass[0].src_hsz = (input_width >> 2) + o; 655 param->f_div.pass[1].o_hsz = h2 - 1; 656 param->f_div.pass[1].i_hps = val1; 657 param->f_div.pass[1].h_phs = (val - (val1 << 8)); 658 param->f_div.pass[1].src_hps = (input_width >> 2) - o; 659 param->f_div.pass[1].src_hsz = (input_width >> 2) + o; 660 661 return 0; 662} 663 664static int 665resizer_configure_in_single_shot_mode(struct vpfe_resizer_device *resizer) 666{ 667 struct vpfe_rsz_config_params *config = &resizer->config.user_config; 668 struct device *dev = resizer->crop_resizer.subdev.v4l2_dev->dev; 669 struct vpfe_device *vpfe_dev = to_vpfe_device(resizer); 670 struct v4l2_mbus_framefmt *outformat1, *outformat2; 671 struct resizer_params *param = &resizer->config; 672 struct v4l2_mbus_framefmt *informat; 673 int decimation; 674 int line_len_c; 675 int line_len; 676 int rsz; 677 int ret; 678 679 informat = &resizer->crop_resizer.formats[RESIZER_CROP_PAD_SINK]; 680 outformat1 = &resizer->resizer_a.formats[RESIZER_PAD_SOURCE]; 681 outformat2 = &resizer->resizer_b.formats[RESIZER_PAD_SOURCE]; 682 683 decimation = vpfe_ipipeif_decimation_enabled(vpfe_dev); 684 rsz = vpfe_ipipeif_get_rsz(vpfe_dev); 685 if (decimation && param->user_config.frame_div_mode_en) { 686 dev_err(dev, 687 "dec_en & frame_div_mode_en cannot enabled simultaneously\n"); 688 return -EINVAL; 689 } 690 691 ret = resizer_validate_decimation(dev, decimation, rsz, 692 param->user_config.frame_div_mode_en, informat->width); 693 if (ret) 694 return -EINVAL; 695 696 ret = resizer_validate_input_image_format(dev, informat->code, 697 informat->width, informat->height, &line_len); 698 if (ret) 699 return -EINVAL; 700 701 if (resizer->resizer_a.output != RESIZER_OUTPUT_NONE) { 702 param->rsz_en[RSZ_A] = ENABLE; 703 ret = resizer_validate_output_image_format(dev, outformat1, 704 &line_len, &line_len_c); 705 if (ret) 706 return ret; 707 param->ext_mem_param[RSZ_A].rsz_sdr_oft_y = line_len; 708 param->ext_mem_param[RSZ_A].rsz_sdr_oft_c = line_len_c; 709 configure_resizer_out_params(resizer, RSZ_A, 710 ¶m->user_config.output1, 0, 1); 711 712 if (outformat1->code == V4L2_MBUS_FMT_SGRBG12_1X12) 713 param->rsz_common.raw_flip = 1; 714 else 715 param->rsz_common.raw_flip = 0; 716 717 if (outformat1->code == V4L2_MBUS_FMT_YDYUYDYV8_1X16) 718 resizer_enable_422_420_conversion(param, 719 RSZ_A, ENABLE); 720 else 721 resizer_enable_422_420_conversion(param, 722 RSZ_A, DISABLE); 723 } 724 725 if (resizer->resizer_b.output != RESIZER_OUTPUT_NONE) { 726 param->rsz_en[RSZ_B] = ENABLE; 727 ret = resizer_validate_output_image_format(dev, outformat2, 728 &line_len, &line_len_c); 729 if (ret) 730 return ret; 731 param->ext_mem_param[RSZ_B].rsz_sdr_oft_y = line_len; 732 param->ext_mem_param[RSZ_B].rsz_sdr_oft_c = line_len_c; 733 configure_resizer_out_params(resizer, RSZ_B, 734 ¶m->user_config.output2, 0, 1); 735 if (outformat2->code == V4L2_MBUS_FMT_YDYUYDYV8_1X16) 736 resizer_enable_422_420_conversion(param, 737 RSZ_B, ENABLE); 738 else 739 resizer_enable_422_420_conversion(param, 740 RSZ_B, DISABLE); 741 } 742 743 resizer_configure_common_in_params(resizer); 744 if (resizer->resizer_a.output != RESIZER_OUTPUT_NONE) { 745 resizer_calculate_resize_ratios(resizer, RSZ_A); 746 resizer_calculate_sdram_offsets(resizer, RSZ_A); 747 /* Overriding resize ratio calculation */ 748 if (informat->code == V4L2_MBUS_FMT_UV8_1X8) { 749 param->rsz_rsc_param[RSZ_A].v_dif = 750 (((informat->height + 1) * 2) * 256) / 751 (param->rsz_rsc_param[RSZ_A].o_vsz + 1); 752 } 753 } 754 755 if (resizer->resizer_b.output != RESIZER_OUTPUT_NONE) { 756 resizer_calculate_resize_ratios(resizer, RSZ_B); 757 resizer_calculate_sdram_offsets(resizer, RSZ_B); 758 /* Overriding resize ratio calculation */ 759 if (informat->code == V4L2_MBUS_FMT_UV8_1X8) { 760 param->rsz_rsc_param[RSZ_B].v_dif = 761 (((informat->height + 1) * 2) * 256) / 762 (param->rsz_rsc_param[RSZ_B].o_vsz + 1); 763 } 764 } 765 if (param->user_config.frame_div_mode_en && 766 param->rsz_en[RSZ_A]) { 767 if (!param->rsz_rsc_param[RSZ_A].dscale_en) 768 ret = resizer_calculate_normal_f_div_param(dev, 769 informat->width, 770 param->rsz_rsc_param[RSZ_A].o_vsz + 1, 771 ¶m->rsz_rsc_param[RSZ_A]); 772 else 773 ret = resizer_calculate_down_scale_f_div_param(dev, 774 informat->width, 775 param->rsz_rsc_param[RSZ_A].o_vsz + 1, 776 ¶m->rsz_rsc_param[RSZ_A]); 777 if (ret) 778 return -EINVAL; 779 } 780 if (param->user_config.frame_div_mode_en && 781 param->rsz_en[RSZ_B]) { 782 if (!param->rsz_rsc_param[RSZ_B].dscale_en) 783 ret = resizer_calculate_normal_f_div_param(dev, 784 informat->width, 785 param->rsz_rsc_param[RSZ_B].o_vsz + 1, 786 ¶m->rsz_rsc_param[RSZ_B]); 787 else 788 ret = resizer_calculate_down_scale_f_div_param(dev, 789 informat->width, 790 param->rsz_rsc_param[RSZ_B].o_vsz + 1, 791 ¶m->rsz_rsc_param[RSZ_B]); 792 if (ret) 793 return -EINVAL; 794 } 795 param->rsz_common.passthrough = config->bypass; 796 if (config->bypass) 797 resizer_configure_passthru(resizer, 1); 798 return 0; 799} 800 801static void 802resizer_set_defualt_configuration(struct vpfe_resizer_device *resizer) 803{ 804#define WIDTH_I 640 805#define HEIGHT_I 480 806#define WIDTH_O 640 807#define HEIGHT_O 480 808 const struct resizer_params rsz_default_config = { 809 .oper_mode = RESIZER_MODE_ONE_SHOT, 810 .rsz_common = { 811 .vsz = HEIGHT_I - 1, 812 .hsz = WIDTH_I - 1, 813 .src_img_fmt = RSZ_IMG_422, 814 .raw_flip = 1, /* flip preserve Raw format */ 815 .source = IPIPE_DATA, 816 .passthrough = BYPASS_OFF, 817 .yuv_y_max = 255, 818 .yuv_c_max = 255, 819 .rsz_seq_crv = DISABLE, 820 .out_chr_pos = VPFE_IPIPE_YUV422_CHR_POS_COSITE, 821 }, 822 .rsz_rsc_param = { 823 { 824 .h_flip = DISABLE, 825 .v_flip = DISABLE, 826 .cen = DISABLE, 827 .yen = DISABLE, 828 .o_vsz = HEIGHT_O - 1, 829 .o_hsz = WIDTH_O - 1, 830 .v_dif = 256, 831 .v_typ_y = VPFE_RSZ_INTP_CUBIC, 832 .h_typ_c = VPFE_RSZ_INTP_CUBIC, 833 .h_dif = 256, 834 .h_typ_y = VPFE_RSZ_INTP_CUBIC, 835 .h_typ_c = VPFE_RSZ_INTP_CUBIC, 836 .h_dscale_ave_sz = 837 VPFE_IPIPE_DWN_SCALE_1_OVER_2, 838 .v_dscale_ave_sz = 839 VPFE_IPIPE_DWN_SCALE_1_OVER_2, 840 }, 841 { 842 .h_flip = DISABLE, 843 .v_flip = DISABLE, 844 .cen = DISABLE, 845 .yen = DISABLE, 846 .o_vsz = HEIGHT_O - 1, 847 .o_hsz = WIDTH_O - 1, 848 .v_dif = 256, 849 .v_typ_y = VPFE_RSZ_INTP_CUBIC, 850 .h_typ_c = VPFE_RSZ_INTP_CUBIC, 851 .h_dif = 256, 852 .h_typ_y = VPFE_RSZ_INTP_CUBIC, 853 .h_typ_c = VPFE_RSZ_INTP_CUBIC, 854 .h_dscale_ave_sz = 855 VPFE_IPIPE_DWN_SCALE_1_OVER_2, 856 .v_dscale_ave_sz = 857 VPFE_IPIPE_DWN_SCALE_1_OVER_2, 858 }, 859 }, 860 .rsz2rgb = { 861 { 862 .rgb_en = DISABLE 863 }, 864 { 865 .rgb_en = DISABLE 866 } 867 }, 868 .ext_mem_param = { 869 { 870 .rsz_sdr_oft_y = WIDTH_O << 1, 871 .rsz_sdr_ptr_e_y = HEIGHT_O, 872 .rsz_sdr_oft_c = WIDTH_O, 873 .rsz_sdr_ptr_e_c = HEIGHT_O >> 1, 874 }, 875 { 876 .rsz_sdr_oft_y = WIDTH_O << 1, 877 .rsz_sdr_ptr_e_y = HEIGHT_O, 878 .rsz_sdr_oft_c = WIDTH_O, 879 .rsz_sdr_ptr_e_c = HEIGHT_O, 880 }, 881 }, 882 .rsz_en[0] = ENABLE, 883 .rsz_en[1] = DISABLE, 884 .user_config = { 885 .output1 = { 886 .v_typ_y = VPFE_RSZ_INTP_CUBIC, 887 .v_typ_c = VPFE_RSZ_INTP_CUBIC, 888 .h_typ_y = VPFE_RSZ_INTP_CUBIC, 889 .h_typ_c = VPFE_RSZ_INTP_CUBIC, 890 .h_dscale_ave_sz = 891 VPFE_IPIPE_DWN_SCALE_1_OVER_2, 892 .v_dscale_ave_sz = 893 VPFE_IPIPE_DWN_SCALE_1_OVER_2, 894 }, 895 .output2 = { 896 .v_typ_y = VPFE_RSZ_INTP_CUBIC, 897 .v_typ_c = VPFE_RSZ_INTP_CUBIC, 898 .h_typ_y = VPFE_RSZ_INTP_CUBIC, 899 .h_typ_c = VPFE_RSZ_INTP_CUBIC, 900 .h_dscale_ave_sz = 901 VPFE_IPIPE_DWN_SCALE_1_OVER_2, 902 .v_dscale_ave_sz = 903 VPFE_IPIPE_DWN_SCALE_1_OVER_2, 904 }, 905 .yuv_y_max = 255, 906 .yuv_c_max = 255, 907 .out_chr_pos = VPFE_IPIPE_YUV422_CHR_POS_COSITE, 908 }, 909 }; 910 memset(&resizer->config, 0, sizeof(struct resizer_params)); 911 memcpy(&resizer->config, &rsz_default_config, 912 sizeof(struct resizer_params)); 913} 914 915/* 916 * resizer_set_configuration() - set resizer config 917 * @resizer: vpfe resizer device pointer. 918 * @chan_config: resizer channel configuration. 919 */ 920static int 921resizer_set_configuration(struct vpfe_resizer_device *resizer, 922 struct vpfe_rsz_config *chan_config) 923{ 924 if (!chan_config->config) 925 resizer_set_defualt_configuration(resizer); 926 else 927 if (copy_from_user(&resizer->config.user_config, 928 chan_config->config, sizeof(struct vpfe_rsz_config_params))) 929 return -EFAULT; 930 931 return 0; 932} 933 934/* 935 * resizer_get_configuration() - get resizer config 936 * @resizer: vpfe resizer device pointer. 937 * @channel: image processor logical channel. 938 * @chan_config: resizer channel configuration. 939 */ 940static int 941resizer_get_configuration(struct vpfe_resizer_device *resizer, 942 struct vpfe_rsz_config *chan_config) 943{ 944 struct device *dev = resizer->crop_resizer.subdev.v4l2_dev->dev; 945 946 if (!chan_config->config) { 947 dev_err(dev, "Resizer channel invalid pointer\n"); 948 return -EINVAL; 949 } 950 951 if (copy_to_user((void *)chan_config->config, 952 (void *)&resizer->config.user_config, 953 sizeof(struct vpfe_rsz_config_params))) { 954 dev_err(dev, "resizer_get_configuration: Error in copy to user\n"); 955 return -EFAULT; 956 } 957 958 return 0; 959} 960 961/* 962 * VPFE video operations 963 */ 964 965/* 966 * resizer_a_video_out_queue() - RESIZER-A video out queue 967 * @vpfe_dev: vpfe device pointer. 968 * @addr: buffer address. 969 */ 970static int resizer_a_video_out_queue(struct vpfe_device *vpfe_dev, 971 unsigned long addr) 972{ 973 struct vpfe_resizer_device *resizer = &vpfe_dev->vpfe_resizer; 974 975 return resizer_set_outaddr(resizer->base_addr, 976 &resizer->config, RSZ_A, addr); 977} 978 979/* 980 * resizer_b_video_out_queue() - RESIZER-B video out queue 981 * @vpfe_dev: vpfe device pointer. 982 * @addr: buffer address. 983 */ 984static int resizer_b_video_out_queue(struct vpfe_device *vpfe_dev, 985 unsigned long addr) 986{ 987 struct vpfe_resizer_device *resizer = &vpfe_dev->vpfe_resizer; 988 989 return resizer_set_outaddr(resizer->base_addr, 990 &resizer->config, RSZ_B, addr); 991} 992 993static const struct vpfe_video_operations resizer_a_video_ops = { 994 .queue = resizer_a_video_out_queue, 995}; 996 997static const struct vpfe_video_operations resizer_b_video_ops = { 998 .queue = resizer_b_video_out_queue, 999}; 1000 1001static void resizer_enable(struct vpfe_resizer_device *resizer, int en) 1002{ 1003 struct vpfe_device *vpfe_dev = to_vpfe_device(resizer); 1004 u16 ipipeif_sink = vpfe_dev->vpfe_ipipeif.input; 1005 unsigned char val; 1006 1007 if (resizer->crop_resizer.input == RESIZER_CROP_INPUT_NONE) 1008 return; 1009 1010 if (resizer->crop_resizer.input == RESIZER_CROP_INPUT_IPIPEIF && 1011 ipipeif_sink == IPIPEIF_INPUT_MEMORY) { 1012 do { 1013 val = regr_rsz(resizer->base_addr, RSZ_SRC_EN); 1014 } while (val); 1015 1016 if (resizer->resizer_a.output != RESIZER_OUTPUT_NONE) { 1017 do { 1018 val = regr_rsz(resizer->base_addr, RSZ_A); 1019 } while (val); 1020 } 1021 if (resizer->resizer_b.output != RESIZER_OUTPUT_NONE) { 1022 do { 1023 val = regr_rsz(resizer->base_addr, RSZ_B); 1024 } while (val); 1025 } 1026 } 1027 if (resizer->resizer_a.output != RESIZER_OUTPUT_NONE) 1028 rsz_enable(resizer->base_addr, RSZ_A, en); 1029 1030 if (resizer->resizer_b.output != RESIZER_OUTPUT_NONE) 1031 rsz_enable(resizer->base_addr, RSZ_B, en); 1032} 1033 1034 1035/* 1036 * resizer_ss_isr() - resizer module single-shot buffer scheduling isr 1037 * @resizer: vpfe resizer device pointer. 1038 */ 1039static void resizer_ss_isr(struct vpfe_resizer_device *resizer) 1040{ 1041 struct vpfe_video_device *video_out = &resizer->resizer_a.video_out; 1042 struct vpfe_video_device *video_out2 = &resizer->resizer_b.video_out; 1043 struct vpfe_device *vpfe_dev = to_vpfe_device(resizer); 1044 struct vpfe_pipeline *pipe = &video_out->pipe; 1045 u16 ipipeif_sink = vpfe_dev->vpfe_ipipeif.input; 1046 u32 val; 1047 1048 if (ipipeif_sink != IPIPEIF_INPUT_MEMORY) 1049 return; 1050 1051 if (resizer->resizer_a.output == RESIZER_OUPUT_MEMORY) { 1052 val = vpss_dma_complete_interrupt(); 1053 if (val != 0 && val != 2) 1054 return; 1055 } 1056 1057 if (resizer->resizer_a.output == RESIZER_OUPUT_MEMORY) { 1058 spin_lock(&video_out->dma_queue_lock); 1059 vpfe_video_process_buffer_complete(video_out); 1060 video_out->state = VPFE_VIDEO_BUFFER_NOT_QUEUED; 1061 vpfe_video_schedule_next_buffer(video_out); 1062 spin_unlock(&video_out->dma_queue_lock); 1063 } 1064 1065 /* If resizer B is enabled */ 1066 if (pipe->output_num > 1 && resizer->resizer_b.output == 1067 RESIZER_OUPUT_MEMORY) { 1068 spin_lock(&video_out->dma_queue_lock); 1069 vpfe_video_process_buffer_complete(video_out2); 1070 video_out2->state = VPFE_VIDEO_BUFFER_NOT_QUEUED; 1071 vpfe_video_schedule_next_buffer(video_out2); 1072 spin_unlock(&video_out2->dma_queue_lock); 1073 } 1074 1075 /* start HW if buffers are queued */ 1076 if (vpfe_video_is_pipe_ready(pipe) && 1077 resizer->resizer_a.output == RESIZER_OUPUT_MEMORY) { 1078 resizer_enable(resizer, 1); 1079 vpfe_ipipe_enable(vpfe_dev, 1); 1080 vpfe_ipipeif_enable(vpfe_dev); 1081 } 1082} 1083 1084/* 1085 * vpfe_resizer_buffer_isr() - resizer module buffer scheduling isr 1086 * @resizer: vpfe resizer device pointer. 1087 */ 1088void vpfe_resizer_buffer_isr(struct vpfe_resizer_device *resizer) 1089{ 1090 struct vpfe_device *vpfe_dev = to_vpfe_device(resizer); 1091 struct vpfe_video_device *video_out = &resizer->resizer_a.video_out; 1092 struct vpfe_video_device *video_out2 = &resizer->resizer_b.video_out; 1093 struct vpfe_pipeline *pipe = &resizer->resizer_a.video_out.pipe; 1094 enum v4l2_field field; 1095 int fid; 1096 1097 if (!video_out->started) 1098 return; 1099 1100 if (resizer->crop_resizer.input == RESIZER_CROP_INPUT_NONE) 1101 return; 1102 1103 field = video_out->fmt.fmt.pix.field; 1104 if (field == V4L2_FIELD_NONE) { 1105 /* handle progressive frame capture */ 1106 if (video_out->cur_frm != video_out->next_frm) { 1107 vpfe_video_process_buffer_complete(video_out); 1108 if (pipe->output_num > 1) 1109 vpfe_video_process_buffer_complete(video_out2); 1110 } 1111 1112 video_out->skip_frame_count--; 1113 if (!video_out->skip_frame_count) { 1114 video_out->skip_frame_count = 1115 video_out->skip_frame_count_init; 1116 rsz_src_enable(resizer->base_addr, 1); 1117 } else { 1118 rsz_src_enable(resizer->base_addr, 0); 1119 } 1120 return; 1121 } 1122 1123 /* handle interlaced frame capture */ 1124 fid = vpfe_isif_get_fid(vpfe_dev); 1125 1126 /* switch the software maintained field id */ 1127 video_out->field_id ^= 1; 1128 if (fid == video_out->field_id) { 1129 /* 1130 * we are in-sync here,continue. 1131 * One frame is just being captured. If the 1132 * next frame is available, release the current 1133 * frame and move on 1134 */ 1135 if (fid == 0 && video_out->cur_frm != video_out->next_frm) { 1136 vpfe_video_process_buffer_complete(video_out); 1137 if (pipe->output_num > 1) 1138 vpfe_video_process_buffer_complete(video_out2); 1139 } 1140 } else if (fid == 0) { 1141 /* 1142 * out of sync. Recover from any hardware out-of-sync. 1143 * May loose one frame 1144 */ 1145 video_out->field_id = fid; 1146 } 1147} 1148 1149/* 1150 * vpfe_resizer_dma_isr() - resizer module dma isr 1151 * @resizer: vpfe resizer device pointer. 1152 */ 1153void vpfe_resizer_dma_isr(struct vpfe_resizer_device *resizer) 1154{ 1155 struct vpfe_video_device *video_out2 = &resizer->resizer_b.video_out; 1156 struct vpfe_video_device *video_out = &resizer->resizer_a.video_out; 1157 struct vpfe_device *vpfe_dev = to_vpfe_device(resizer); 1158 struct vpfe_pipeline *pipe = &video_out->pipe; 1159 int schedule_capture = 0; 1160 enum v4l2_field field; 1161 int fid; 1162 1163 if (!video_out->started) 1164 return; 1165 1166 if (pipe->state == VPFE_PIPELINE_STREAM_SINGLESHOT) { 1167 resizer_ss_isr(resizer); 1168 return; 1169 } 1170 1171 field = video_out->fmt.fmt.pix.field; 1172 if (field == V4L2_FIELD_NONE) { 1173 if (!list_empty(&video_out->dma_queue) && 1174 video_out->cur_frm == video_out->next_frm) 1175 schedule_capture = 1; 1176 } else { 1177 fid = vpfe_isif_get_fid(vpfe_dev); 1178 if (fid == video_out->field_id) { 1179 /* we are in-sync here,continue */ 1180 if (fid == 1 && !list_empty(&video_out->dma_queue) && 1181 video_out->cur_frm == video_out->next_frm) 1182 schedule_capture = 1; 1183 } 1184 } 1185 1186 if (!schedule_capture) 1187 return; 1188 1189 spin_lock(&video_out->dma_queue_lock); 1190 vpfe_video_schedule_next_buffer(video_out); 1191 spin_unlock(&video_out->dma_queue_lock); 1192 if (pipe->output_num > 1) { 1193 spin_lock(&video_out2->dma_queue_lock); 1194 vpfe_video_schedule_next_buffer(video_out2); 1195 spin_unlock(&video_out2->dma_queue_lock); 1196 } 1197} 1198 1199/* 1200 * V4L2 subdev operations 1201 */ 1202 1203/* 1204 * resizer_ioctl() - Handle resizer module private ioctl's 1205 * @sd: pointer to v4l2 subdev structure 1206 * @cmd: configuration command 1207 * @arg: configuration argument 1208 */ 1209static long resizer_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) 1210{ 1211 struct vpfe_resizer_device *resizer = v4l2_get_subdevdata(sd); 1212 struct device *dev = resizer->crop_resizer.subdev.v4l2_dev->dev; 1213 struct vpfe_rsz_config *user_config; 1214 int ret = -ENOIOCTLCMD; 1215 1216 if (&resizer->crop_resizer.subdev != sd) 1217 return ret; 1218 1219 switch (cmd) { 1220 case VIDIOC_VPFE_RSZ_S_CONFIG: 1221 user_config = (struct vpfe_rsz_config *)arg; 1222 ret = resizer_set_configuration(resizer, user_config); 1223 break; 1224 1225 case VIDIOC_VPFE_RSZ_G_CONFIG: 1226 user_config = (struct vpfe_rsz_config *)arg; 1227 if (!user_config->config) { 1228 dev_err(dev, "error in VIDIOC_VPFE_RSZ_G_CONFIG\n"); 1229 return -EINVAL; 1230 } 1231 ret = resizer_get_configuration(resizer, user_config); 1232 break; 1233 } 1234 return ret; 1235} 1236 1237static int resizer_do_hw_setup(struct vpfe_resizer_device *resizer) 1238{ 1239 struct vpfe_device *vpfe_dev = to_vpfe_device(resizer); 1240 u16 ipipeif_sink = vpfe_dev->vpfe_ipipeif.input; 1241 u16 ipipeif_source = vpfe_dev->vpfe_ipipeif.output; 1242 struct resizer_params *param = &resizer->config; 1243 int ret = 0; 1244 1245 if (resizer->resizer_a.output == RESIZER_OUPUT_MEMORY || 1246 resizer->resizer_b.output == RESIZER_OUPUT_MEMORY) { 1247 if (ipipeif_sink == IPIPEIF_INPUT_MEMORY && 1248 ipipeif_source == IPIPEIF_OUTPUT_RESIZER) 1249 ret = resizer_configure_in_single_shot_mode(resizer); 1250 else 1251 ret = resizer_configure_in_continious_mode(resizer); 1252 if (ret) 1253 return ret; 1254 ret = config_rsz_hw(resizer, param); 1255 } 1256 return ret; 1257} 1258 1259/* 1260 * resizer_set_stream() - Enable/Disable streaming on resizer subdev 1261 * @sd: pointer to v4l2 subdev structure 1262 * @enable: 1 == Enable, 0 == Disable 1263 */ 1264static int resizer_set_stream(struct v4l2_subdev *sd, int enable) 1265{ 1266 struct vpfe_resizer_device *resizer = v4l2_get_subdevdata(sd); 1267 1268 if (&resizer->crop_resizer.subdev != sd) 1269 return 0; 1270 1271 if (resizer->resizer_a.output != RESIZER_OUPUT_MEMORY) 1272 return 0; 1273 1274 switch (enable) { 1275 case 1: 1276 if (resizer_do_hw_setup(resizer) < 0) 1277 return -EINVAL; 1278 resizer_enable(resizer, enable); 1279 break; 1280 1281 case 0: 1282 resizer_enable(resizer, enable); 1283 break; 1284 } 1285 1286 return 0; 1287} 1288 1289/* 1290 * __resizer_get_format() - helper function for getting resizer format 1291 * @sd: pointer to subdev. 1292 * @fh: V4L2 subdev file handle. 1293 * @pad: pad number. 1294 * @which: wanted subdev format. 1295 * Retun wanted mbus frame format. 1296 */ 1297static struct v4l2_mbus_framefmt * 1298__resizer_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, 1299 unsigned int pad, enum v4l2_subdev_format_whence which) 1300{ 1301 struct vpfe_resizer_device *resizer = v4l2_get_subdevdata(sd); 1302 1303 if (which == V4L2_SUBDEV_FORMAT_TRY) 1304 return v4l2_subdev_get_try_format(fh, pad); 1305 if (&resizer->crop_resizer.subdev == sd) 1306 return &resizer->crop_resizer.formats[pad]; 1307 if (&resizer->resizer_a.subdev == sd) 1308 return &resizer->resizer_a.formats[pad]; 1309 if (&resizer->resizer_b.subdev == sd) 1310 return &resizer->resizer_b.formats[pad]; 1311 return NULL; 1312} 1313 1314/* 1315 * resizer_try_format() - Handle try format by pad subdev method 1316 * @sd: pointer to subdev. 1317 * @fh: V4L2 subdev file handle. 1318 * @pad: pad num. 1319 * @fmt: pointer to v4l2 format structure. 1320 * @which: wanted subdev format. 1321 */ 1322static void 1323resizer_try_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, 1324 unsigned int pad, struct v4l2_mbus_framefmt *fmt, 1325 enum v4l2_subdev_format_whence which) 1326{ 1327 struct vpfe_resizer_device *resizer = v4l2_get_subdevdata(sd); 1328 unsigned int max_out_height; 1329 unsigned int max_out_width; 1330 unsigned int i; 1331 1332 if ((&resizer->resizer_a.subdev == sd && pad == RESIZER_PAD_SINK) || 1333 (&resizer->resizer_b.subdev == sd && pad == RESIZER_PAD_SINK) || 1334 (&resizer->crop_resizer.subdev == sd && 1335 (pad == RESIZER_CROP_PAD_SOURCE || 1336 pad == RESIZER_CROP_PAD_SOURCE2 || pad == RESIZER_CROP_PAD_SINK))) { 1337 for (i = 0; i < ARRAY_SIZE(resizer_input_formats); i++) { 1338 if (fmt->code == resizer_input_formats[i]) 1339 break; 1340 } 1341 /* If not found, use UYVY as default */ 1342 if (i >= ARRAY_SIZE(resizer_input_formats)) 1343 fmt->code = V4L2_MBUS_FMT_UYVY8_2X8; 1344 1345 fmt->width = clamp_t(u32, fmt->width, MIN_IN_WIDTH, 1346 MAX_IN_WIDTH); 1347 fmt->height = clamp_t(u32, fmt->height, MIN_IN_HEIGHT, 1348 MAX_IN_HEIGHT); 1349 } else if (&resizer->resizer_a.subdev == sd && 1350 pad == RESIZER_PAD_SOURCE) { 1351 max_out_width = IPIPE_MAX_OUTPUT_WIDTH_A; 1352 max_out_height = IPIPE_MAX_OUTPUT_HEIGHT_A; 1353 1354 for (i = 0; i < ARRAY_SIZE(resizer_output_formats); i++) { 1355 if (fmt->code == resizer_output_formats[i]) 1356 break; 1357 } 1358 /* If not found, use UYVY as default */ 1359 if (i >= ARRAY_SIZE(resizer_output_formats)) 1360 fmt->code = V4L2_MBUS_FMT_UYVY8_2X8; 1361 1362 fmt->width = clamp_t(u32, fmt->width, MIN_OUT_WIDTH, 1363 max_out_width); 1364 fmt->width &= ~15; 1365 fmt->height = clamp_t(u32, fmt->height, MIN_OUT_HEIGHT, 1366 max_out_height); 1367 } else if (&resizer->resizer_b.subdev == sd && 1368 pad == RESIZER_PAD_SOURCE) { 1369 max_out_width = IPIPE_MAX_OUTPUT_WIDTH_B; 1370 max_out_height = IPIPE_MAX_OUTPUT_HEIGHT_B; 1371 1372 for (i = 0; i < ARRAY_SIZE(resizer_output_formats); i++) { 1373 if (fmt->code == resizer_output_formats[i]) 1374 break; 1375 } 1376 /* If not found, use UYVY as default */ 1377 if (i >= ARRAY_SIZE(resizer_output_formats)) 1378 fmt->code = V4L2_MBUS_FMT_UYVY8_2X8; 1379 1380 fmt->width = clamp_t(u32, fmt->width, MIN_OUT_WIDTH, 1381 max_out_width); 1382 fmt->width &= ~15; 1383 fmt->height = clamp_t(u32, fmt->height, MIN_OUT_HEIGHT, 1384 max_out_height); 1385 } 1386} 1387 1388/* 1389 * resizer_set_format() - Handle set format by pads subdev method 1390 * @sd: pointer to v4l2 subdev structure 1391 * @fh: V4L2 subdev file handle 1392 * @fmt: pointer to v4l2 subdev format structure 1393 * return -EINVAL or zero on success 1394 */ 1395static int resizer_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, 1396 struct v4l2_subdev_format *fmt) 1397{ 1398 struct vpfe_resizer_device *resizer = v4l2_get_subdevdata(sd); 1399 struct v4l2_mbus_framefmt *format; 1400 1401 format = __resizer_get_format(sd, fh, fmt->pad, fmt->which); 1402 if (format == NULL) 1403 return -EINVAL; 1404 1405 resizer_try_format(sd, fh, fmt->pad, &fmt->format, fmt->which); 1406 *format = fmt->format; 1407 1408 if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) 1409 return 0; 1410 1411 if (&resizer->crop_resizer.subdev == sd) { 1412 if (fmt->pad == RESIZER_CROP_PAD_SINK) { 1413 resizer->crop_resizer.formats[fmt->pad] = fmt->format; 1414 } else if (fmt->pad == RESIZER_CROP_PAD_SOURCE && 1415 resizer->crop_resizer.output == RESIZER_A) { 1416 resizer->crop_resizer.formats[fmt->pad] = fmt->format; 1417 resizer->crop_resizer. 1418 formats[RESIZER_CROP_PAD_SOURCE2] = fmt->format; 1419 } else if (fmt->pad == RESIZER_CROP_PAD_SOURCE2 && 1420 resizer->crop_resizer.output2 == RESIZER_B) { 1421 resizer->crop_resizer.formats[fmt->pad] = fmt->format; 1422 resizer->crop_resizer. 1423 formats[RESIZER_CROP_PAD_SOURCE] = fmt->format; 1424 } else { 1425 return -EINVAL; 1426 } 1427 } else if (&resizer->resizer_a.subdev == sd) { 1428 if (fmt->pad == RESIZER_PAD_SINK) 1429 resizer->resizer_a.formats[fmt->pad] = fmt->format; 1430 else if (fmt->pad == RESIZER_PAD_SOURCE) 1431 resizer->resizer_a.formats[fmt->pad] = fmt->format; 1432 else 1433 return -EINVAL; 1434 } else if (&resizer->resizer_b.subdev == sd) { 1435 if (fmt->pad == RESIZER_PAD_SINK) 1436 resizer->resizer_b.formats[fmt->pad] = fmt->format; 1437 else if (fmt->pad == RESIZER_PAD_SOURCE) 1438 resizer->resizer_b.formats[fmt->pad] = fmt->format; 1439 else 1440 return -EINVAL; 1441 } else { 1442 return -EINVAL; 1443 } 1444 1445 return 0; 1446} 1447 1448/* 1449 * resizer_get_format() - Retrieve the video format on a pad 1450 * @sd: pointer to v4l2 subdev structure. 1451 * @fh: V4L2 subdev file handle. 1452 * @fmt: pointer to v4l2 subdev format structure 1453 * return -EINVAL or zero on success 1454 */ 1455static int resizer_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, 1456 struct v4l2_subdev_format *fmt) 1457{ 1458 struct v4l2_mbus_framefmt *format; 1459 1460 format = __resizer_get_format(sd, fh, fmt->pad, fmt->which); 1461 if (format == NULL) 1462 return -EINVAL; 1463 1464 fmt->format = *format; 1465 1466 return 0; 1467} 1468 1469/* 1470 * resizer_enum_frame_size() - enum frame sizes on pads 1471 * @sd: Pointer to subdevice. 1472 * @fh: V4L2 subdev file handle. 1473 * @code: pointer to v4l2_subdev_frame_size_enum structure. 1474 */ 1475static int resizer_enum_frame_size(struct v4l2_subdev *sd, 1476 struct v4l2_subdev_fh *fh, 1477 struct v4l2_subdev_frame_size_enum *fse) 1478{ 1479 struct v4l2_mbus_framefmt format; 1480 1481 if (fse->index != 0) 1482 return -EINVAL; 1483 1484 format.code = fse->code; 1485 format.width = 1; 1486 format.height = 1; 1487 resizer_try_format(sd, fh, fse->pad, &format, 1488 V4L2_SUBDEV_FORMAT_TRY); 1489 fse->min_width = format.width; 1490 fse->min_height = format.height; 1491 1492 if (format.code != fse->code) 1493 return -EINVAL; 1494 1495 format.code = fse->code; 1496 format.width = -1; 1497 format.height = -1; 1498 resizer_try_format(sd, fh, fse->pad, &format, 1499 V4L2_SUBDEV_FORMAT_TRY); 1500 fse->max_width = format.width; 1501 fse->max_height = format.height; 1502 1503 return 0; 1504} 1505 1506/* 1507 * resizer_enum_mbus_code() - enum mbus codes for pads 1508 * @sd: Pointer to subdevice. 1509 * @fh: V4L2 subdev file handle 1510 * @code: pointer to v4l2_subdev_mbus_code_enum structure 1511 */ 1512static int resizer_enum_mbus_code(struct v4l2_subdev *sd, 1513 struct v4l2_subdev_fh *fh, 1514 struct v4l2_subdev_mbus_code_enum *code) 1515{ 1516 if (code->pad == RESIZER_PAD_SINK) { 1517 if (code->index >= ARRAY_SIZE(resizer_input_formats)) 1518 return -EINVAL; 1519 1520 code->code = resizer_input_formats[code->index]; 1521 } else if (code->pad == RESIZER_PAD_SOURCE) { 1522 if (code->index >= ARRAY_SIZE(resizer_output_formats)) 1523 return -EINVAL; 1524 1525 code->code = resizer_output_formats[code->index]; 1526 } 1527 1528 return 0; 1529} 1530 1531/* 1532 * resizer_init_formats() - Initialize formats on all pads 1533 * @sd: Pointer to subdevice. 1534 * @fh: V4L2 subdev file handle. 1535 * 1536 * Initialize all pad formats with default values. If fh is not NULL, try 1537 * formats are initialized on the file handle. Otherwise active formats are 1538 * initialized on the device. 1539 */ 1540static int resizer_init_formats(struct v4l2_subdev *sd, 1541 struct v4l2_subdev_fh *fh) 1542{ 1543 __u32 which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; 1544 struct vpfe_resizer_device *resizer = v4l2_get_subdevdata(sd); 1545 struct v4l2_subdev_format format; 1546 1547 if (&resizer->crop_resizer.subdev == sd) { 1548 memset(&format, 0, sizeof(format)); 1549 format.pad = RESIZER_CROP_PAD_SINK; 1550 format.which = which; 1551 format.format.code = V4L2_MBUS_FMT_YUYV8_2X8; 1552 format.format.width = MAX_IN_WIDTH; 1553 format.format.height = MAX_IN_HEIGHT; 1554 resizer_set_format(sd, fh, &format); 1555 1556 memset(&format, 0, sizeof(format)); 1557 format.pad = RESIZER_CROP_PAD_SOURCE; 1558 format.which = which; 1559 format.format.code = V4L2_MBUS_FMT_UYVY8_2X8; 1560 format.format.width = MAX_IN_WIDTH; 1561 format.format.height = MAX_IN_WIDTH; 1562 resizer_set_format(sd, fh, &format); 1563 1564 memset(&format, 0, sizeof(format)); 1565 format.pad = RESIZER_CROP_PAD_SOURCE2; 1566 format.which = which; 1567 format.format.code = V4L2_MBUS_FMT_UYVY8_2X8; 1568 format.format.width = MAX_IN_WIDTH; 1569 format.format.height = MAX_IN_WIDTH; 1570 resizer_set_format(sd, fh, &format); 1571 } else if (&resizer->resizer_a.subdev == sd) { 1572 memset(&format, 0, sizeof(format)); 1573 format.pad = RESIZER_PAD_SINK; 1574 format.which = which; 1575 format.format.code = V4L2_MBUS_FMT_YUYV8_2X8; 1576 format.format.width = MAX_IN_WIDTH; 1577 format.format.height = MAX_IN_HEIGHT; 1578 resizer_set_format(sd, fh, &format); 1579 1580 memset(&format, 0, sizeof(format)); 1581 format.pad = RESIZER_PAD_SOURCE; 1582 format.which = which; 1583 format.format.code = V4L2_MBUS_FMT_UYVY8_2X8; 1584 format.format.width = IPIPE_MAX_OUTPUT_WIDTH_A; 1585 format.format.height = IPIPE_MAX_OUTPUT_HEIGHT_A; 1586 resizer_set_format(sd, fh, &format); 1587 } else if (&resizer->resizer_b.subdev == sd) { 1588 memset(&format, 0, sizeof(format)); 1589 format.pad = RESIZER_PAD_SINK; 1590 format.which = which; 1591 format.format.code = V4L2_MBUS_FMT_YUYV8_2X8; 1592 format.format.width = MAX_IN_WIDTH; 1593 format.format.height = MAX_IN_HEIGHT; 1594 resizer_set_format(sd, fh, &format); 1595 1596 memset(&format, 0, sizeof(format)); 1597 format.pad = RESIZER_PAD_SOURCE; 1598 format.which = which; 1599 format.format.code = V4L2_MBUS_FMT_UYVY8_2X8; 1600 format.format.width = IPIPE_MAX_OUTPUT_WIDTH_B; 1601 format.format.height = IPIPE_MAX_OUTPUT_HEIGHT_B; 1602 resizer_set_format(sd, fh, &format); 1603 } 1604 1605 return 0; 1606} 1607 1608/* subdev core operations */ 1609static const struct v4l2_subdev_core_ops resizer_v4l2_core_ops = { 1610 .ioctl = resizer_ioctl, 1611}; 1612 1613/* subdev internal operations */ 1614static const struct v4l2_subdev_internal_ops resizer_v4l2_internal_ops = { 1615 .open = resizer_init_formats, 1616}; 1617 1618/* subdev video operations */ 1619static const struct v4l2_subdev_video_ops resizer_v4l2_video_ops = { 1620 .s_stream = resizer_set_stream, 1621}; 1622 1623/* subdev pad operations */ 1624static const struct v4l2_subdev_pad_ops resizer_v4l2_pad_ops = { 1625 .enum_mbus_code = resizer_enum_mbus_code, 1626 .enum_frame_size = resizer_enum_frame_size, 1627 .get_fmt = resizer_get_format, 1628 .set_fmt = resizer_set_format, 1629}; 1630 1631/* subdev operations */ 1632static const struct v4l2_subdev_ops resizer_v4l2_ops = { 1633 .core = &resizer_v4l2_core_ops, 1634 .video = &resizer_v4l2_video_ops, 1635 .pad = &resizer_v4l2_pad_ops, 1636}; 1637 1638/* 1639 * Media entity operations 1640 */ 1641 1642/* 1643 * resizer_link_setup() - Setup resizer connections 1644 * @entity: Pointer to media entity structure 1645 * @local: Pointer to local pad array 1646 * @remote: Pointer to remote pad array 1647 * @flags: Link flags 1648 * return -EINVAL or zero on success 1649 */ 1650static int resizer_link_setup(struct media_entity *entity, 1651 const struct media_pad *local, 1652 const struct media_pad *remote, u32 flags) 1653{ 1654 struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); 1655 struct vpfe_resizer_device *resizer = v4l2_get_subdevdata(sd); 1656 struct vpfe_device *vpfe_dev = to_vpfe_device(resizer); 1657 u16 ipipeif_source = vpfe_dev->vpfe_ipipeif.output; 1658 u16 ipipe_source = vpfe_dev->vpfe_ipipe.output; 1659 1660 if (&resizer->crop_resizer.subdev == sd) { 1661 switch (local->index | media_entity_type(remote->entity)) { 1662 case RESIZER_CROP_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV: 1663 if (!(flags & MEDIA_LNK_FL_ENABLED)) { 1664 resizer->crop_resizer.input = 1665 RESIZER_CROP_INPUT_NONE; 1666 break; 1667 } 1668 1669 if (resizer->crop_resizer.input != 1670 RESIZER_CROP_INPUT_NONE) 1671 return -EBUSY; 1672 if (ipipeif_source == IPIPEIF_OUTPUT_RESIZER) 1673 resizer->crop_resizer.input = 1674 RESIZER_CROP_INPUT_IPIPEIF; 1675 else if (ipipe_source == IPIPE_OUTPUT_RESIZER) 1676 resizer->crop_resizer.input = 1677 RESIZER_CROP_INPUT_IPIPE; 1678 else 1679 return -EINVAL; 1680 break; 1681 1682 case RESIZER_CROP_PAD_SOURCE | MEDIA_ENT_T_V4L2_SUBDEV: 1683 if (!(flags & MEDIA_LNK_FL_ENABLED)) { 1684 resizer->crop_resizer.output = 1685 RESIZER_CROP_OUTPUT_NONE; 1686 break; 1687 } 1688 if (resizer->crop_resizer.output != 1689 RESIZER_CROP_OUTPUT_NONE) 1690 return -EBUSY; 1691 resizer->crop_resizer.output = RESIZER_A; 1692 break; 1693 1694 case RESIZER_CROP_PAD_SOURCE2 | MEDIA_ENT_T_V4L2_SUBDEV: 1695 if (!(flags & MEDIA_LNK_FL_ENABLED)) { 1696 resizer->crop_resizer.output2 = 1697 RESIZER_CROP_OUTPUT_NONE; 1698 break; 1699 } 1700 if (resizer->crop_resizer.output2 != 1701 RESIZER_CROP_OUTPUT_NONE) 1702 return -EBUSY; 1703 resizer->crop_resizer.output2 = RESIZER_B; 1704 break; 1705 1706 default: 1707 return -EINVAL; 1708 } 1709 } else if (&resizer->resizer_a.subdev == sd) { 1710 switch (local->index | media_entity_type(remote->entity)) { 1711 case RESIZER_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV: 1712 if (!(flags & MEDIA_LNK_FL_ENABLED)) { 1713 resizer->resizer_a.input = RESIZER_INPUT_NONE; 1714 break; 1715 } 1716 if (resizer->resizer_a.input != RESIZER_INPUT_NONE) 1717 return -EBUSY; 1718 resizer->resizer_a.input = RESIZER_INPUT_CROP_RESIZER; 1719 break; 1720 1721 case RESIZER_PAD_SOURCE | MEDIA_ENT_T_DEVNODE: 1722 if (!(flags & MEDIA_LNK_FL_ENABLED)) { 1723 resizer->resizer_a.output = RESIZER_OUTPUT_NONE; 1724 break; 1725 } 1726 if (resizer->resizer_a.output != RESIZER_OUTPUT_NONE) 1727 return -EBUSY; 1728 resizer->resizer_a.output = RESIZER_OUPUT_MEMORY; 1729 break; 1730 1731 default: 1732 return -EINVAL; 1733 } 1734 } else if (&resizer->resizer_b.subdev == sd) { 1735 switch (local->index | media_entity_type(remote->entity)) { 1736 case RESIZER_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV: 1737 if (!(flags & MEDIA_LNK_FL_ENABLED)) { 1738 resizer->resizer_b.input = RESIZER_INPUT_NONE; 1739 break; 1740 } 1741 if (resizer->resizer_b.input != RESIZER_INPUT_NONE) 1742 return -EBUSY; 1743 resizer->resizer_b.input = RESIZER_INPUT_CROP_RESIZER; 1744 break; 1745 1746 case RESIZER_PAD_SOURCE | MEDIA_ENT_T_DEVNODE: 1747 if (!(flags & MEDIA_LNK_FL_ENABLED)) { 1748 resizer->resizer_b.output = RESIZER_OUTPUT_NONE; 1749 break; 1750 } 1751 if (resizer->resizer_b.output != RESIZER_OUTPUT_NONE) 1752 return -EBUSY; 1753 resizer->resizer_b.output = RESIZER_OUPUT_MEMORY; 1754 break; 1755 1756 default: 1757 return -EINVAL; 1758 } 1759 } else { 1760 return -EINVAL; 1761 } 1762 1763 return 0; 1764} 1765 1766static const struct media_entity_operations resizer_media_ops = { 1767 .link_setup = resizer_link_setup, 1768}; 1769 1770/* 1771 * vpfe_resizer_unregister_entities() - Unregister entity 1772 * @vpfe_rsz - pointer to resizer subdevice structure. 1773 */ 1774void vpfe_resizer_unregister_entities(struct vpfe_resizer_device *vpfe_rsz) 1775{ 1776 /* unregister video devices */ 1777 vpfe_video_unregister(&vpfe_rsz->resizer_a.video_out); 1778 vpfe_video_unregister(&vpfe_rsz->resizer_b.video_out); 1779 1780 /* unregister subdev */ 1781 v4l2_device_unregister_subdev(&vpfe_rsz->crop_resizer.subdev); 1782 v4l2_device_unregister_subdev(&vpfe_rsz->resizer_a.subdev); 1783 v4l2_device_unregister_subdev(&vpfe_rsz->resizer_b.subdev); 1784 /* cleanup entity */ 1785 media_entity_cleanup(&vpfe_rsz->crop_resizer.subdev.entity); 1786 media_entity_cleanup(&vpfe_rsz->resizer_a.subdev.entity); 1787 media_entity_cleanup(&vpfe_rsz->resizer_b.subdev.entity); 1788} 1789 1790/* 1791 * vpfe_resizer_register_entities() - Register entity 1792 * @resizer - pointer to resizer devive. 1793 * @vdev: pointer to v4l2 device structure. 1794 */ 1795int vpfe_resizer_register_entities(struct vpfe_resizer_device *resizer, 1796 struct v4l2_device *vdev) 1797{ 1798 struct vpfe_device *vpfe_dev = to_vpfe_device(resizer); 1799 unsigned int flags = 0; 1800 int ret; 1801 1802 /* Register the crop resizer subdev */ 1803 ret = v4l2_device_register_subdev(vdev, &resizer->crop_resizer.subdev); 1804 if (ret < 0) { 1805 pr_err("Failed to register crop resizer as v4l2-subdev\n"); 1806 return ret; 1807 } 1808 /* Register Resizer-A subdev */ 1809 ret = v4l2_device_register_subdev(vdev, &resizer->resizer_a.subdev); 1810 if (ret < 0) { 1811 pr_err("Failed to register resizer-a as v4l2-subdev\n"); 1812 return ret; 1813 } 1814 /* Register Resizer-B subdev */ 1815 ret = v4l2_device_register_subdev(vdev, &resizer->resizer_b.subdev); 1816 if (ret < 0) { 1817 pr_err("Failed to register resizer-b as v4l2-subdev\n"); 1818 return ret; 1819 } 1820 /* Register video-out device for resizer-a */ 1821 ret = vpfe_video_register(&resizer->resizer_a.video_out, vdev); 1822 if (ret) { 1823 pr_err("Failed to register RSZ-A video-out device\n"); 1824 goto out_video_out2_register; 1825 } 1826 resizer->resizer_a.video_out.vpfe_dev = vpfe_dev; 1827 1828 /* Register video-out device for resizer-b */ 1829 ret = vpfe_video_register(&resizer->resizer_b.video_out, vdev); 1830 if (ret) { 1831 pr_err("Failed to register RSZ-B video-out device\n"); 1832 goto out_video_out2_register; 1833 } 1834 resizer->resizer_b.video_out.vpfe_dev = vpfe_dev; 1835 1836 /* create link between Resizer Crop----> Resizer A*/ 1837 ret = media_entity_create_link(&resizer->crop_resizer.subdev.entity, 1, 1838 &resizer->resizer_a.subdev.entity, 1839 0, flags); 1840 if (ret < 0) 1841 goto out_create_link; 1842 1843 /* create link between Resizer Crop----> Resizer B*/ 1844 ret = media_entity_create_link(&resizer->crop_resizer.subdev.entity, 2, 1845 &resizer->resizer_b.subdev.entity, 1846 0, flags); 1847 if (ret < 0) 1848 goto out_create_link; 1849 1850 /* create link between Resizer A ----> video out */ 1851 ret = media_entity_create_link(&resizer->resizer_a.subdev.entity, 1, 1852 &resizer->resizer_a.video_out.video_dev.entity, 0, flags); 1853 if (ret < 0) 1854 goto out_create_link; 1855 1856 /* create link between Resizer B ----> video out */ 1857 ret = media_entity_create_link(&resizer->resizer_b.subdev.entity, 1, 1858 &resizer->resizer_b.video_out.video_dev.entity, 0, flags); 1859 if (ret < 0) 1860 goto out_create_link; 1861 1862 return 0; 1863 1864out_create_link: 1865 vpfe_video_unregister(&resizer->resizer_b.video_out); 1866out_video_out2_register: 1867 vpfe_video_unregister(&resizer->resizer_a.video_out); 1868 v4l2_device_unregister_subdev(&resizer->crop_resizer.subdev); 1869 v4l2_device_unregister_subdev(&resizer->resizer_a.subdev); 1870 v4l2_device_unregister_subdev(&resizer->resizer_b.subdev); 1871 media_entity_cleanup(&resizer->crop_resizer.subdev.entity); 1872 media_entity_cleanup(&resizer->resizer_a.subdev.entity); 1873 media_entity_cleanup(&resizer->resizer_b.subdev.entity); 1874 return ret; 1875} 1876 1877/* 1878 * vpfe_resizer_init() - resizer device initialization. 1879 * @vpfe_rsz - pointer to resizer device 1880 * @pdev: platform device pointer. 1881 */ 1882int vpfe_resizer_init(struct vpfe_resizer_device *vpfe_rsz, 1883 struct platform_device *pdev) 1884{ 1885 struct v4l2_subdev *sd = &vpfe_rsz->crop_resizer.subdev; 1886 struct media_pad *pads = &vpfe_rsz->crop_resizer.pads[0]; 1887 struct media_entity *me = &sd->entity; 1888 static resource_size_t res_len; 1889 struct resource *res; 1890 int ret; 1891 1892 res = platform_get_resource(pdev, IORESOURCE_MEM, 5); 1893 if (!res) 1894 return -ENOENT; 1895 1896 res_len = resource_size(res); 1897 res = request_mem_region(res->start, res_len, res->name); 1898 if (!res) 1899 return -EBUSY; 1900 1901 vpfe_rsz->base_addr = ioremap_nocache(res->start, res_len); 1902 if (!vpfe_rsz->base_addr) 1903 return -EBUSY; 1904 1905 v4l2_subdev_init(sd, &resizer_v4l2_ops); 1906 sd->internal_ops = &resizer_v4l2_internal_ops; 1907 strlcpy(sd->name, "DAVINCI RESIZER CROP", sizeof(sd->name)); 1908 sd->grp_id = 1 << 16; /* group ID for davinci subdevs */ 1909 v4l2_set_subdevdata(sd, vpfe_rsz); 1910 sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; 1911 1912 pads[RESIZER_CROP_PAD_SINK].flags = MEDIA_PAD_FL_SINK; 1913 pads[RESIZER_CROP_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; 1914 pads[RESIZER_CROP_PAD_SOURCE2].flags = MEDIA_PAD_FL_SOURCE; 1915 1916 vpfe_rsz->crop_resizer.input = RESIZER_CROP_INPUT_NONE; 1917 vpfe_rsz->crop_resizer.output = RESIZER_CROP_OUTPUT_NONE; 1918 vpfe_rsz->crop_resizer.output2 = RESIZER_CROP_OUTPUT_NONE; 1919 vpfe_rsz->crop_resizer.rsz_device = vpfe_rsz; 1920 me->ops = &resizer_media_ops; 1921 ret = media_entity_init(me, RESIZER_CROP_PADS_NUM, pads, 0); 1922 if (ret) 1923 return ret; 1924 1925 sd = &vpfe_rsz->resizer_a.subdev; 1926 pads = &vpfe_rsz->resizer_a.pads[0]; 1927 me = &sd->entity; 1928 1929 v4l2_subdev_init(sd, &resizer_v4l2_ops); 1930 sd->internal_ops = &resizer_v4l2_internal_ops; 1931 strlcpy(sd->name, "DAVINCI RESIZER A", sizeof(sd->name)); 1932 sd->grp_id = 1 << 16; /* group ID for davinci subdevs */ 1933 v4l2_set_subdevdata(sd, vpfe_rsz); 1934 sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; 1935 1936 pads[RESIZER_PAD_SINK].flags = MEDIA_PAD_FL_SINK; 1937 pads[RESIZER_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; 1938 1939 vpfe_rsz->resizer_a.input = RESIZER_INPUT_NONE; 1940 vpfe_rsz->resizer_a.output = RESIZER_OUTPUT_NONE; 1941 vpfe_rsz->resizer_a.rsz_device = vpfe_rsz; 1942 me->ops = &resizer_media_ops; 1943 ret = media_entity_init(me, RESIZER_PADS_NUM, pads, 0); 1944 if (ret) 1945 return ret; 1946 1947 sd = &vpfe_rsz->resizer_b.subdev; 1948 pads = &vpfe_rsz->resizer_b.pads[0]; 1949 me = &sd->entity; 1950 1951 v4l2_subdev_init(sd, &resizer_v4l2_ops); 1952 sd->internal_ops = &resizer_v4l2_internal_ops; 1953 strlcpy(sd->name, "DAVINCI RESIZER B", sizeof(sd->name)); 1954 sd->grp_id = 1 << 16; /* group ID for davinci subdevs */ 1955 v4l2_set_subdevdata(sd, vpfe_rsz); 1956 sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; 1957 1958 pads[RESIZER_PAD_SINK].flags = MEDIA_PAD_FL_SINK; 1959 pads[RESIZER_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; 1960 1961 vpfe_rsz->resizer_b.input = RESIZER_INPUT_NONE; 1962 vpfe_rsz->resizer_b.output = RESIZER_OUTPUT_NONE; 1963 vpfe_rsz->resizer_b.rsz_device = vpfe_rsz; 1964 me->ops = &resizer_media_ops; 1965 ret = media_entity_init(me, RESIZER_PADS_NUM, pads, 0); 1966 if (ret) 1967 return ret; 1968 1969 vpfe_rsz->resizer_a.video_out.ops = &resizer_a_video_ops; 1970 vpfe_rsz->resizer_a.video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 1971 ret = vpfe_video_init(&vpfe_rsz->resizer_a.video_out, "RSZ-A"); 1972 if (ret) { 1973 pr_err("Failed to init RSZ video-out device\n"); 1974 return ret; 1975 } 1976 vpfe_rsz->resizer_b.video_out.ops = &resizer_b_video_ops; 1977 vpfe_rsz->resizer_b.video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 1978 ret = vpfe_video_init(&vpfe_rsz->resizer_b.video_out, "RSZ-B"); 1979 if (ret) { 1980 pr_err("Failed to init RSZ video-out2 device\n"); 1981 return ret; 1982 } 1983 memset(&vpfe_rsz->config, 0, sizeof(struct resizer_params)); 1984 1985 return 0; 1986} 1987 1988void 1989vpfe_resizer_cleanup(struct vpfe_resizer_device *vpfe_rsz, 1990 struct platform_device *pdev) 1991{ 1992 struct resource *res; 1993 1994 iounmap(vpfe_rsz->base_addr); 1995 res = platform_get_resource(pdev, IORESOURCE_MEM, 5); 1996 if (res) 1997 release_mem_region(res->start, 1998 resource_size(res)); 1999} 2000