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